8

Is there some alternative to Mockito's Answer in ScalaTest? I was going through its documentation, but didn't find anything.

I would like to, for example, execute some logic on arguments of a stubbed method. In Mockito, I would do something like this:

when(mock.create(any(A.class))).thenAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
        A firstArg = (A) invocation.getArguments()[0];
        firstArg.callMethod();
        return null;
    }
});

In ScalaTest, I'm fine with using Mockito, as well. However, it would be nice if there was some more Scala-friendly syntax of defining such Answer.

Thank you.

semberal
  • 2,204
  • 1
  • 21
  • 21

4 Answers4

11

I just found this blog post. It describes how to use implicit conversions to achieve what you want. If you define an implicit conversion like this

implicit def toAnswerWithArgs[T](f: InvocationOnMock => T) = new Answer[T] {
    override def answer(i: InvocationOnMock): T = f(i)
}

you can call thenAnswer with a simple function as argument:

when(mock.someMethodCall()).thenAnswer((i) => calculateReturnValue())

There is also a slightly shorter alternative version for the case when your mocked method has no arguments. Follow the link for details.

lex82
  • 11,173
  • 2
  • 44
  • 69
  • So much cleaner as, after adding the implicits, doReturn can be replaced directly with doAnswer when the return value need recomputation on request. – Pyrce Apr 19 '18 at 20:22
3

Define this helper function:

def answer[T](f: InvocationOnMock => T): Answer[T] = {
  new Answer[T] {
    override def answer(invocation: InvocationOnMock): T = f(invocation)
  }
}

And use it like this, e.g. for returning a Future[MyClass] containing any argument passed to a method:

when(myRepository.create(any[MyClass]())).thenAnswer(answer({ invocation =>
  Future.successful(invocation.getArguments.head.asInstanceOf[MyClass])
}))
Fernando Correia
  • 21,803
  • 13
  • 83
  • 116
2

If you mix in the trait MockitoSugar, you can create a mock and and pass it an answer using this syntax:

mock[Collaborator](new Answer(){ ... })
yakshaver
  • 2,472
  • 1
  • 18
  • 21
1

Have you tried ScalaMock? It is also integrated with ScalaTest and provides a more Scala-friendly API.

rs_atl
  • 8,935
  • 1
  • 23
  • 28
  • I'm in the process of migrating from mockito to ScalaMock, and was wondering how one can actually do something like `InvocationOnMock` in ScalaMock. Turns out it was super easy and just like I would have wanted to do in mockito: just have some impure/mutative function that is wrappen in ScalaMock's `returns`: like `...when(...).returns(updateCount())` – bbarker Oct 26 '17 at 21:25