Forming Mockito "grammars"
Mockito seems like a pretty sweet stubbing/mocking framework for Java. The only problem is I can't find any concrete documentation on the best ways of using their API. Common methods used in tests include:
doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber
When you see examples of Mockito in practice, you see code like:
when(yourMethod()).thenReturn(5);
From all the docs I've read, I've identified several "patterns" of Mockito "grammars" obtained from daisy-chaining these method calls together like the example above. Some common patterns I've found are:
When/Then: when(yourMethod()).thenReturn(5);
Given/Will: given(yourMethod()).willThrow(OutOfMemoryException.class);
Do/When: doReturn(7).when(yourMock.fizzBuzz());
Will/Given/Do: willReturn(any()).given(yourMethod()).doNothing();
Verify/Do: verify(yourMethod()).doThrow(SomeException.class);
What I'm choking on is how to select the right pattern/combination of method calls to model my test cases. It seems like you can daisy-chain these together in seemingly endless combos and I'm not sure what pattern is right for which problem.
Can some Mockito Guru help shed some light as to which patterns/combinations of Mockito methods are used for which types of test cases (and why)? Thanks in advance!
Solution 1:
There are several disadvantages to the when/thenReturn
, when/thenThrow
and when/then
syntaxes. For example,
- In the case of
when/thenReturn
, if the return type is a generic with a wildcard, and you wish to return a mock of the same type, you will be unable to avoid a compile warning. - You can't use
when/thenThrow
andwhen/then
for a void method. - You can't use these syntaxes on Mockito spies.
- You can only call
when
once for each combination of mock object, method and arguments, unless you callreset
on the mock. - Calling
when
multiple times for one combination of mock object and method, when you are using argument matchers, can lead to problems.
I find these cases difficult to remember. So instead of trying to keep track of when the
when/thenReturn
, when/thenThrow
and when/then
syntaxes will and won't work, I prefer to avoid them completely, in favour of the doReturn/when
, doThrow/when
and doAnswer/when
alternatives. That is to say, since you'll occasionally need doReturn/when
, doThrow/when
and doAnswer/when
, and you can ALWAYS use these methods, there is no point in learning how to use when/thenReturn
, when/thenThrow
and when/then
.
Note that doReturn
, doThrow
and doAnswer
can be chained together in the same way as thenReturn
, thenThrow
and then
. What they don't have is an option for returning several values (or throwing several exceptions, or running several answers) within a single call to doReturn
, doThrow
and doAnswer
. But I find that I need to do this so seldom, that it doesn't really matter.
There's one more disadvantage to doReturn
, which I consider insignificant. You don't get compile time checking of the type of its argument, like you do with when/thenReturn
. So if you get the argument type wrong, you won't find out until you run your test. Frankly, I don't care.
In summary then, I have been using Mockito for more than two years, and I consider the consistent use of doReturn
, doThrow
and doAnswer
to be a Mockito best practice. Other Mockito users disagree.
Solution 2:
Mockito often have several ways of doing things.
I find myself using mostly:
// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());
// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();
I've found that i can do 95% of what i need to with these three kinds of calls.
Also, what version of Mockito are you using? "given" and "will" constructs are not present in the latest version (1.9.0+)
However, there are cases where I want the return value or exception to respond to the input. In this case, you can use the Answer interface to inspect the method arguments and return an appropriate value.
public class ReturnFirstArg<T> implements Answer<T> {
public T answer(InvocationOnMock invocation) {
return invocation.getArguments()[0];
}
}
when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());
Solution 3:
The things in fact looks much simpler than you thought
REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html
Verify:
In order to use Mockito, you need to understand one basic philosophy of Mockito: Stubbing and Verification is separated. Therefore, the "Verify/Do" you mentioned is in fact doing the "Verification" job, while the other 4 "grammars" is for stubbing. Stubbing define how the mock object will react in different situation. Verification is to make sure what the mocks is invoked as expected, in previous invocation to system under test (SUT).
When/Then , Given/Will:
Then it come to the "When" and "Given" families. You can simply treat them as aliases of each other. "Given" family is added in Mockito 1.8.x as to make it looks more aligned to BDD practices.
DoXxx:
In normal case we mostly use when(xxx).then(...)
(and given(...).will(...)
) . However there are some case that syntax is not working. The most obvious case is when return type of the stubbed method is void. In such case when(mockObj.voidMethod()).thenThrow(anException)
is not going to compile. As a workaround, an alternative syntax of Do/When is created, so you can write the previous line as doThrow(anException).when(mockObj.voidMethod())