1

I'm using mockito spy with this code:

Mockito.doAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
         ImagesSorter mock = (ImagesSorter) invocation.getMock();
         Object[] args = invocation.getArguments();

         return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
                 fakeNowDate);
    }
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

And I see the answer() is called eagerly when the struct is:

when(spy.method())./*...*/.

but it's lazy evaluation when the struct is:

/*...*/.when(spy).method()

Shouldn't it be vise versa? Meaning /*...*/.when(spy).method() is eager versus when(spy.method())./*...*/. is lazy? Like do..while loop ?

I couldn't find documentation for that

Elad Benda
  • 35,076
  • 87
  • 265
  • 471

2 Answers2

4

One thing you should notice about this syntax:

when(spy.method()).thenAnswer(someAnswer);

Is that the first thing Java will do when evaluating it is to run:

     spy.method()

...so that it can pass an accurate return value into the when method. Of course, when discards its parameter and just reads the last call to a mock, but Java can't know that from the syntax. For the very first call to when on a mock, the method should have no exceptions or side effects, but that assumption doesn't hold on spies or on methods that you've already stubbed.


In general, doAnswer and other doVerb methods have two key uses: stubbing void methods and overriding already-defined behavior (i.e. for spies and already-stubbed methods).

Void methods

// Doesn't work: voidMethod has no return value, so when() has no parameter
when(yourMock.voidMethod()).thenThrow(new RuntimeException());
// This works, because it skips reading the voidMethod return value:
doThrow(new RuntimeException()).when(yourMock).voidMethod();

Already-stubbed methods

// Doesn't work: This contains a call to dangerousMethod!
when(yourSpy.dangerousMethod()).thenReturn(safeValue);
// This works, because the call to dangerousMethod happens on a dummy copy of yourSpy:
doReturn(safeValue).when(yourSpy).dangerousMethod();

As noted in lkrnac's answer, Mockito describes this latter case in the "important gotcha on spying real objects!" in top-level Mockito documentation.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
0

I believe that the /*...*/.when(spy).method() syntax for spies is Mockito implementation detail. If you think about that, how would you implement Mockito functionality to stub method on spy in this call when(spy.method())./*...*/, when you don't want to call real method? You need to have different API for spies because API used for mocks is not suitable.

Here is relevant documentation (see section "Important gotcha on spying real objects!"): https://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/Mockito.html#13

luboskrnac
  • 23,973
  • 10
  • 81
  • 92