Using MockitoJunitRunner
rather than JunitRunner
is really optional.
The automatic validation of framework usage is actually worth having.
It gives you better reporting if you make one of these mistakes.
The main advantage provided by MockitoJunitRunner
is relieving you to explicitly invoke MockitoAnnotations.initMocks(Object)
when you use the @Mock
way to create your mocks.
But you could also get a few more misuse reports of the Mockito framework by using this runner that may be missing without using it.
The javadoc of the Mockito 1.10.19
version states :
Compatible with JUnit 4.4 and higher, this runner adds following
behavior:
Initializes mocks annotated with Mock, so that explicit usage of
MockitoAnnotations.initMocks(Object)
is not necessary. Mocks are
initialized before each test method.
validates framework usage after each test method. See javadoc for
Mockito.validateMockitoUsage().
And the most important part :
Runner is completely optional - there are other ways you can get @Mock
working, for example by writing a base class. Explicitly validating
framework usage is also optional because it is triggered automatically
by Mockito every time you use the framework. See javadoc for
Mockito.validateMockitoUsage()
.
Example of incorrect uses that may be caught out of the box without using the MockitoJunitRunner
:
//Oops, thenReturn() part is missing:
when(mock.get());
//Oops, verified method call is inside verify() where it should be on the outside:
verify(mock.execute());
//Oops, missing method to verify:
verify(mock);
But these could not be caught in all cases.
The Mockito.validateMockitoUsage()
method that is invoked by the runner and the framework itself gives more explanations about it but in fact it is not complete.
validateMockitoUsage()
explicitly validates the framework state to
detect invalid use of Mockito. However, this feature is optional
because Mockito validates the usage all the time... but there is a
gotcha so read on.
Ok. Go on.
Mockito throws exceptions if you misuse it so that you know if your
tests are written correctly. The gotcha is that Mockito does the
validation next time you use the framework (e.g. next time you verify,
stub, call mock etc.). But even though the exception might be thrown
in the next test, the exception message contains a navigable stack
trace element with location of the defect. Hence you can click and
find the place where Mockito was misused.
So, the framework does the validation the next time you use the framework (verify, stub, call mock,etc..).
In fact it is true but not always.
For example this misuse will be caught by the framework :
@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.verify(mock.getAddressLine());
}
org.mockito.exceptions.misusing.NullInsteadOfMockException: Argument
passed to verify() should be a mock but is null!
But this misuse will not be caught :
@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.when(mock.getAddressLine());
}
While if I add a new use of Mockito after this uncaught misuse, this time we will get a validation exception :
@Test
public void testBadUseWhen() throws Exception {
Address mock = Mockito.mock(Address.class);
Mockito.when(mock.getAddressLine());
Mockito.when(mock.getAddressLine());
}
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here
It will be raised for the second Mockito.when(mock.getAddressLine());
statement invoked but the exception will reference the first Mockito.when(mock.getAddressLine());
statement invoked.
It means that for some bad uses of the framework, you could lose the report information if the last mockito method you are used is incorrectly used.
The javadoc states then :
Sometimes though, you might want to validate the framework usage
explicitly. For example, one of the users wanted to put
validateMockitoUsage() in his @After method so that he knows
immediately when he misused Mockito. Without it, he would have known
about it not sooner than next time he used the framework. One more
benefit of having validateMockitoUsage() in @After is that jUnit
runner and rule will always fail in the test method with defect
whereas ordinary 'next-time' validation might fail the next test
method. But even though JUnit might report next test as red, don't
worry about it and just click at navigable stack trace element in the
exception message to instantly locate the place where you misused
mockito.
So, to not loosing a potentially misuse for the last one Mockito method invoked during a test class, you can explicitly invoke Mockito.validateMockitoUsage()
after each tested method.
So this will do the trick :
@After
public void after() {
Mockito.validateMockitoUsage();
}
The alternative is using the MockitoJUnitRunner
that under the hood invokes Mockito.validateMockitoUsage()
after each executed test :
@Override
public void testFinished(Description description) throws Exception {
super.testFinished(description);
try {
Mockito.validateMockitoUsage();
} catch(Throwable t) {
notifier.fireTestFailure(new Failure(description, t));
}
}