3

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)
}
Yormi
  • 479
  • 1
  • 5
  • 14
  • 1
    So the `org.mockito.Mockito.reset` method on your mock repo didn't work? – Eric Apr 30 '15 at 22:10
  • Oh Yeah ! That works ! I feel a bit stupid now... I tried only `reset(eventRepoMock)` ... but... what is the difference with `org.mockito.Mockito.reset(eventRepoMock)` if I call it in a class that extends Mockito ? – Yormi May 01 '15 at 07:28
  • I added a question to the original question post as well – Yormi May 01 '15 at 09:17
  • Can you please post a full snipped (but simplified as much as possible)? – Eric May 01 '15 at 10:26
  • Can you also try to make your specification `sequential`? By default examples are executed concurrently and this might be why you see your tests failing. – Eric May 01 '15 at 23:36
  • `... def is = sequential ^ s2""" ...` – Eric May 01 '15 at 23:37
  • That's what I was looking for ! You are a my hero ! Thank you Eric :) – Yormi May 02 '15 at 18:02
  • I added a more complete answer, also using the `BeforeAll` and `BeforeEach` traits. – Eric May 03 '15 at 03:04

1 Answers1

3

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)
  }
}
Eric
  • 15,494
  • 38
  • 61
  • Have you made it works with `BeforeEach` ? For me, I needed to use the deprecated `BeforeExample` instead because otherwise `before` was not called... – Yormi May 03 '15 at 06:46
  • `BeforeExample` is defined as `trait BeforeExample extends BeforeEach ` so that should definitely work. – Eric May 03 '15 at 09:10
  • It should be simple, just changing the import and extends/with, right ? When I try it, the before method is just not called. Nothing in the logger and all the tests crash. Nonetheless, I can live with the deprecated `BeforeExample` for now. I just wanted to mention it. If someone ever encounters the same problem than me, maybe I can spare him some time. Thanks again Eric ! – Yormi May 03 '15 at 09:34