|
UsingMockito
Using Mockito mocks and stubs.
IntroductionMockito is a mocking library which "lets you write beautiful tests with clean & simple API". specs integrates Mockito expectations and add some syntactic sugar for an even simpler experience of Mockito. UsageIn order to use Mockito mocks in your specification, you need to mix in the Mockito trait. import org.specs.Specification
import org.specs.mock.Mockito
import org.mockito.Matchers._ // to use matchers like anyInt()
object spec extends Specification with Mockito {
val m = mock[java.util.List[String]] // a concrete class would be mocked with: mock(new java.util.LinkedList[String])
// stub a method call with a return value
m.get(0) returns "one"
// call the method
m.get(0)
// verify that the call happened, this is an expectation which will throw a FailureException if that is not the case
m.get(0) was called
// we can also check that another call did not occur
m.get(1) wasnt called // or m.get(1) was notCalled
}
StubbingStubbing values is as simple as calling a method on the mock and declaring what should be returned or thrown: m.get(1) returns "one"
m.get(2) throws new Exception("forbidden")
You can specify different consecutive returned values by appending thenReturns or thenThrows: m.get(1) returns "one" thenReturns "two"
m.get(2) throws new Exception("forbidden") thenReturns "999"
Smart mocksMocks can be made to return "smart" null values (look at setting smart return values for more details): trait Hello {
def get(i: Int) = "hello"
}
val m = smartMock[Hello]
m.get(0) must ==("") // instead of nullNote: there is an internal Mockito bug when doing the same thing on java.util.ListString Argument matchersThe built-in Mockito argument matchers can be used to specify the method arguments for stubbing: mockedList.get(anyInt()) returns "element" mockedList.get(999) must_== "element" Hamcrest matchers can also be used, allowing to create your own Hamcrest matchers: // stubbing using hamcrest (let's say IsNull returns your own hamcrest matcher): mockedList.contains(argThat(new IsNull)) returns true While Mockito matchers are pretty exhaustive, for convenience a any[T] matcher is available: // the any matcher calls the org.mockito.Matchers.isA(classOf[T]) method mockedList.contains(any[String]) was called You can even pass specs matchers directly as arguments where the implicit conversion would work: mockedList.get(==(123)) returns "one" // ==(_) is an alias for beEqualTo(_) // note that the implicit conversion transforming a specs Matcher to a Hamcrest matcher would not work here as the expected type for the contains method is Object mockedList.contains(isNull) returns true CallbacksIn some rare cases, it is necessary to have the return value depend on the parameters passed to the mocked method: val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString }
}The function passed to answers will be called with each parameter passed to the stubbed method: // returns The parameter is 0 s.mockedList.get(0) // The second call returns a different value: The parameter is 1 s.mockedList.get(1) Parameters for the answers functionBecause of the use of reflection the function passed to answers will receive only instances of the java.lang.Object type. More precisely, it will:
VerificationBy default Mockito doesn't expect any method to be called. However if your writing interaction-based specifications you want to specify that some methods are indeed called: mockedList.get(0) mockedList.get(0) was called mockedList.get(1) wasnt called mockedList.get(2) was notCalled If anything fails a new FailureException will be thrown creating a failure for the current example. Constraints on call expectationsYou can be more precise when specifying the number of calls on a mock: val mockedList = mock[List[String]]
mockedList.add("one")
2.times { i => mockedList.add("two") }
3.times { i => mockedList.add("three") }
mockedList.add("one") was called.once
mockedList.add("two") was called.twice
mockedList.add("two") was called.atLeastOnce
// fails with The method was not called as expected: list.add("one"); Wanted 2 times but was 1
mockedList.add("one") was called.twice
// It is also possible to check that there are no unexpected calls on a mock:
mockedList had noMoreCalls
Order of callsThe order of method calls can be checked by creating calls and chaining them with then: val m1 = mock[List[String]] val m2 = mock[List[String]] m1.get(0) m1.get(0) m2.get(0) // mock calls theMethod(m1.get(0)).on(m1).twice then theMethod(m2.get(0)).on(m2) were called.inOrder The implicit definition can also be removed but additional parenthesis are needed: (m1.get(0) on m1).twice then
(m2.get(0) on m2) were calledInOrder // alias for called.inOrderSpiesSpies can also be used in order to do some "partial mocking" of real objects:
val spiedList = spy(new LinkedList[String])
// methods can be stubbed on a spy
spiedList.size returns 100
// other methods can also be used
spiedList.add("one")
spiedList.add("two")
// and verification can happen on a spy
spiedList.add("one") was calledHowever, working with spies can be tricky: // if the list is empty, this will throws an IndexOutOfBoundsException spiedList.get(0) returns "one" As advised in the Mockito documentation, doReturn must be used in that case: doReturn("one").when(spiedList).get(0)
|
Sign in to add a comment
here are the instructions for depending Mockito with Maven: http://code.google.com/p/mockito/wiki/MavenUsers