Reputation: 402
Ok this is weird. Mockito, Java, on windows.
when(mongoTemplate.findAndModify(any(Query.class), any(Update.class), any(FindAndModifyOptions.class), eq(Task.class)))
.thenReturn(t1)
.thenReturn(t2);
Now if I run this in debug mode it works fine. But if I put a break point on the when, and single step it fails.
The error in IntelliJ is
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Task cannot be returned by toString()
toString() should return String
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
So this is possibly some interaction with IntelliJ wanting to "toString()" the result while single stepping. Maybe Mockito needs to catch and fallback on toString on OngoingStubbing?
Upvotes: 2
Views: 952
Reputation: 95654
This behavior is intentional, and has to be, or else toString
would be unstubbable or unusable.
Mockito stubbing works via side-effects and proxying. For a call like yours:
when(mongoTemplate.findAndModify(any(Query.class), any(Update.class), any(FindAndModifyOptions.class), eq(Task.class)))
.thenReturn(t1)
.thenReturn(t2);
Mockito takes advantage of the predictable Java execution order, which evaluates method arguments in order and then the method call itself, so it sees:
any(Query.class)
: 1 matcher on the argument matcher stack, return null
any(Update.class)
: 2 matchers on the stack, return null
any(FindAndModifyOptions.class)
: 3 matchers on the stack, return null
eq(Task.class)
: 4 matchers on the stack, return null
findAndModify(null, null, null, null)
: Return what findAndModify
returns, findAndModify
is now the most recent callwhen
: we're now mocking most recent call findAndModify
with four argument matchers, reset the stackthenReturn(t1)
: Add an action onto the stubbing chain that when
returnedthenReturn(t2)
: Add an action onto the stubbing chain that when
returnedIf your IDE calls toString
between steps 5 and 6, then Mockito will assume that you called findAndModify(null, null, null, null)
intentionally earlier and are trying to stub toString
now. Since you're trying to return t1
, that means that Mockito will tell you that your stub of toString()
expects a String but receives a Task.
Though this is annoying, it's arguably less annoying than if Mockito refused to stub toString()
, or if you were entirely unable to call toString()
on a mock.
Upvotes: 5