找到你要的答案

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

Q:如何重新利用scalatra,specs2模拟调用计数器,Mockito

I never expected that I will need to ask a question on this site because everything is already answered normally but with Scalatra... I haven't find a lot of information so here it is:

I'm not experienced with all that so maybe I'm missing something but from what I understand, if I want to test the API that I develop on Scalatra, I need to start the server everytime I run the test suit, right ?

Second question, how can I reset the invocation counter on a method so I don't have to calculate how many times the method has been called since the beginning of the test suite ? Right now using this give me more than one because it counts the previous test.

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

I can still get around the problem by either counting or putting the test as first test for now but it's not a sustainable solution...

Other thing that I found: Reset method on the mock... not found http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#17

Isolating the test in a class scope: We need to add

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

and we can't repeat the addServlet at every initialization https://etorreborre.github.io/specs2/guide/SPECS2-3.5/org.specs2.guide.Isolation.html

Last thing that I try is:

servlet.repo = mock[EventRepo]

but repo being a value, I can't change it like this.

Neither of these "solutions" feel very clean so I was wondering if someone had a genius idea that can solve that mess !?

Thank you in advance !

EDIT: Thanks to Eric's comment the above question are solve(that was easy) but now I have problem because I'm testing the get/post which are asynchronous call so resetting the mock does not happen at the right time... Any suggestion ?

Here's a simplified version of the code:

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)
}

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

我没有,也许我错过了一些东西但我知道了,如果我想要测试的API,开发Scalatra,我需要启动服务器每次运行测试服,对吗?

第二个问题,我怎样才能重置方法上的调用计数器,所以我不需要计算测试开始以来调用了多少次方法?现在使用这个给我一个以上,因为它计数以前的测试。

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

我仍然可以通过计数或把测试作为第一次测试的问题,但它不是一个可持续的解决方案…

Other thing that I found: Reset method on the mock... not found http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#17

Isolating the test in a class scope: We need to add

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

and we can't repeat the addServlet at every initialization https://etorreborre.github.io/specs2/guide/SPECS2-3.5/org.specs2.guide.Isolation.html

我尝试的最后一件事是:

servlet.repo = mock[EventRepo]

但回购是一个价值,我不能改变它像这样。

这两个“解决方案”感觉非常干净,所以我想知道如果有人有天才的想法,可以解决这个烂摊子!?

提前谢谢!

EDIT: Thanks to Eric's comment the above question are solve(that was easy) but now I have problem because I'm testing the get/post which are asynchronous call so resetting the mock does not happen at the right time... Any suggestion ?

这里有一个简化版的代码:

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)
}
answer1: 回答1:

All org.mockito.Mockito functions can still be used in a specs2 specification and reset is one of them.

Now, since you are sharing the state of a mock object across several examples, you not only need to reset the mock state before each example but you also need to make your specification 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)
  }
}

所有的org.mockito.mockito功能还是可以用在specs2规范和复位是其中之一。

现在,由于您在多个示例中共享模拟对象的状态,您不仅需要在每个示例之前重置模拟状态,而且还需要使您的规范顺序:

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)
  }
}
unit-testing  mockito  specs2  scalatra