The setup is as follows:
//call doA a bunch of times, call doB once using some value that depends on doA()
verify(mockedThing).doB(eq(mockedThing.doA())); //remo
Jeff Bowman's answer helps explain what is going on.
A lot of Mockito is based on the last-called function, and calls to mocks implicitly check state in ways that aren't compatible with the syntax you're trying to use. I wrote a bit more on this answer here. – Jeff Bowman yesterday
As mentioned in my comment, Mockito is actually stateful in unintuitive ways; many times the method stubbed or verified is simply the "last called method", mostly because syntax like verify(foo).doA()
actually calls doA
rather than passing a reflective reference to the method doA
into Mockito. This simply isn't compatible with syntax that calls the same mock in the middle of stubbing or verification.
I've written about this before with regard to Matchers, which have the same problem during stubbing. Poking through the source code, you can see the same problem with verification, at least when calling a method on the same mock.
In short, verification is actually a three phase process:
verify(mockedThing)
.mockedThing
.mockedThing
, with actual parameter values if you're not using matchers, and dummy (ignored) parameter values if you are using matchers. Since Mockito keeps track of the matchers stack in the background, matcher methods can return 0
or null
without Mockito thinking those are values to check against.Calls to verify actually just set a flag and return the exact same mock:
public <T> T verify(T mock, VerificationMode mode) {
// [catch errors]
mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, mode));
return mock;
}
Then, inside the handler that handles all mock invocations, Mockito starts verification on the first call to the mock that happens once verification is started:
public Object handle(Invocation invocation) throws Throwable {
// [detect doAnswer stubbing]
VerificationMode verificationMode = mockingProgress.pullVerificationMode();
// [check Matcher state]
// if verificationMode is not null then someone is doing verify()
if (verificationMode != null) {
// We need to check if verification was started on the correct mock
// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) {
VerificationDataImpl data = createVerificationData(invocationContainerImpl, invocationMatcher);
verificationMode.verify(data);
return null;
} else {
// this means there is an invocation on a different mock. Re-adding verification mode
// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
mockingProgress.verificationStarted(verificationMode);
}
}
// [prepare invocation for stubbing]
}
Therefore, if you interact with the mock just to get a parameter value, Mockito is going to assume that you're actually calling the method to verify. Note that if the call was slightly different, like verify(mockedThing).doB(eq(5), eq(mockedThing.doA()));
with the extra eq(5)
, you'd get a different error message about misusing matchers—specifically because Mockito doesn't just think you're verifying doA
, but that you somehow think doA
takes an argument.
Your code doesn't work:
// DOESN'T WORK
verify(mockedThing).doB(eq(mockedThing.doA()));
// BECAUSE IT BEHAVES THE SAME AS
verify(mockedThing).doA();
But extracting it does work:
// WORKS, though it makes an extra call to doA
Value value = mockedThing.doA();
verify(mockedThing).doB(eq(value));
And this also works, and shows off what's happening under the covers, but don't ever write this in a real test:
// WORKS BUT DON'T EVER ACTUALLY DO THIS
Value value = mockedThing.doA();
verify(mockedThing);
eq(value);
mockedThing.doB(8675309 /* dummy value ignored because of matcher */);