18/2/2013
Mockito provides a facility to respond to a method call with an Answer
, allowing you to access the actual arguments and respond appropriately.
To use this, you need to implement the usual single-method interface which Java uses for closures. Now, while closure support may finally be coming in Java 8, and Scala 2.10 may add automatic conversions of single-method interfaces to closures, in Scala 2.9 the call looks quite ugly:
when(this.mock.method(any())).thenAnswer(new Answer[ReturnType] {
override def answer(invocation: InvocationOnMock): ReturnType = {
//return something
}
}
It would be much nicer to be able to just pass a closure:
when(this.mock.method(any())).thenAnswer((invocation: InvocationOnMock) => {
//return something
})
Or, when there are no arguments or we don't care about the actual arguments, even:
when(this.mock.method()).thenAnswer(() => {
//return something
})
Thankfully, we can help ourselves with implicit conversions:
implicit def toAnswerWithArguments[T](f: (InvocationOnMock) => T): Answer[T] = new Answer[T] {
override def answer(invocation: InvocationOnMock): T = f(invocation)
}
implicit def toAnswer[T](f: () => T): Answer[T] = new Answer[T] {
override def answer(invocation: InvocationOnMock): T = f()
}
These implicit conversion will wrap a closure into the required Answer
type used by Mockito, allowing the desirable closure syntax shown above.
Now just wrap these into a trait to mix into your test classes, and you're done:
trait AnswerSugar {
implicit def toAnswer[T](f: () => T): Answer[T] = new Answer[T] {
override def answer(invocation: InvocationOnMock): T = f()
}
implicit def toAnswerWithArguments[T](f: (InvocationOnMock) => T): Answer[T] = new Answer[T] {
override def answer(invocation: InvocationOnMock): T = f(invocation)
}
}