如何使用 Scalatra、Specs2、Mockito 重置模拟调用计数器

How to reset a mock invocation counter using Scalatra, Specs2, Mockito

我从没想过我需要在这个网站上提问,因为一切都已经正常回答了,但是使用 Scalatra...我没有找到很多信息,所以这里是:

我对这一切都没有经验,所以也许我遗漏了一些东西,但据我了解,如果我想测试我在 Scalatra 上开发的 API,我需要每次都启动服务器我运行测试服对吧?

第二个问题,如何重置方法的调用计数器,这样我就不必计算自测试套件开始以来该方法被调用了多少次?现在使用这个给我不止一个,因为它计算了以前的测试。

there was one(*instance*).*method*(*parameter*)

我现在仍然可以通过计算或将测试作为第一个测试来解决这个问题,但这不是一个可持续的解决方案...

我发现的其他东西: 模拟上的重置方法...未找到 http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#17

在 class 范围内隔离测试: 我们需要添加

val servlet = new Servlet(eventRepoMock)
addServlet(servlet, "/*")

而且我们不能在每次初始化时都重复 addServlet https://etorreborre.github.io/specs2/guide/SPECS2-3.5/org.specs2.guide.Isolation.html

我最后尝试的是:

servlet.repo = mock[EventRepo]

但是 repo 作为一个值,我不能这样改变它。

这些 "solutions" 都感觉不太干净所以我想知道是否有人有一个天才的想法可以解决这个问题!?

提前致谢!

编辑: 感谢 Eric 的评论,上面的问题已经解决(这很容易)但是现在我遇到了问题,因为我正在测试异步调用的 get/post 所以重置模拟不会在正确的时间发生......任何建议?

这是代码的简化版本:

class EventServiceSpec extends ScalatraSpec with Mockito with Before { def is = s2"""
Event Service

GET an existing event
must return status 200                              $get_status200
must return the event with id = :id                 $get_rightEventElement
must call findById once on the event repository     $get_findByIdOnRepo
"""

lazy val anEvent = Event(1, "Some Event"
lazy val eventsBaseUrl = "/events"
lazy val existingEventUrl = s"$eventsBaseUrl/${anEvent.id}"

lazy val eventRepoMock = mock[EventRepository]

lazy val servlet = new Servlet(eventRepoMock)
addServlet(servlet, "/*")

def before = {
    eventRepoMock.findById(anEvent.id) returns Option(anEvent)
    eventRepoMock.findById(unexistingId) returns None
    eventRepoMock.save(anEvent) returns Option(anEvent)
}

def get_status200 = get(existingEventUrl){
    status must_== 200
}

def get_findByIdOnRepo = get(existingEventUrl){
    // TODO count considering previous test... need to find a cleaner way
    there was three(eventRepoMock).findById(anEvent.id)
}

所有 org.mockito.Mockito 函数仍然可以在 specs2 规范中使用,reset 是其中之一。

现在,由于您要在多个示例之间共享模拟对象的状态,因此您不仅需要在每个示例之前重置模拟状态,还需要制定规范 sequential:

class EventServiceSpec extends ScalatraSpec with Mockito 
  with BeforeAll with BeforeEach { 
  def is = sequential ^ s2"""
  Event Service

  GET an existing event
    must return status 200                              $get_status200
    must return the event with id = :id                 $get_rightEventElement
    must call findById once on the event repository  $get_findByIdOnRepo
  """

  lazy val anEvent = Event(1, "Some Event")
  lazy val eventsBaseUrl = "/events"
  lazy val existingEventUrl = s"$eventsBaseUrl/${anEvent.id}"

  lazy val eventRepoMock = mock[EventRepository]

  lazy val servlet = new Servlet(eventRepoMock)

  def beforeAll = addServlet(servlet, "/*")

  def before = {
    reset(eventRepoMock)
    eventRepoMock.findById(anEvent.id) returns Option(anEvent)
    eventRepoMock.findById(unexistingId) returns None
    eventRepoMock.save(anEvent) returns Option(anEvent)
  }

  def get_status200 = get(existingEventUrl){
    status must_== 200
  }

  def get_findByIdOnRepo = get(existingEventUrl){
   there was one(eventRepoMock).findById(anEvent.id)
  }
}