Using Mockito Answers with Scala 2.9

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

}

Comments