With IS 7.10 the Mockito libraries are updated from version 1 to version 2. Since this is an upgrade to a new major version, some migration effort is necessary, when using Mockito for testing.
Using Mockito 2 may help to improve the quality of tests, mainly using by the following points
The methods anyX() do not accept null values anymore. So code smells can be shown in the tests and the tested code.
Getting arguments for InvocationOnMock does not need the class as an argument anymore. Therefore the following changes are necessary
-PaymentContext context = invocation.getArgumentAt(0, PaymentContext.class); -Payable payable = invocation.getArgumentAt(1, Payable.class); +PaymentContext context = invocation.getArgument(0); +Payable payable = invocation.getArgument(1);
The Matchers.argThat
method family, which depended on Hamcrest was reworked and moved to a new API. Therefore the following adaptions are necessary:
-import static org.mockito.Mockito.argThat; +import static org.mockito.hamcrest.MockitoHamcrest.argThat;
The Junit runner of Mockito 2 was move to a new package. The old runner will probably be removed in Mockito 3
-import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner;
The Mockito Matchers are moved to ArgumentMatchers. The old Matchers will probably be removed in Mockito 3
-import static org.mockito.Matchers.*; +import static org.mockito.ArgumentMatchers.*;
The strict runner is default runner in Mockito 2. This runner detects unused stubs within tests and throws an UnnecessaryStubbingException in these cases.
import org.mockito.junit.MockitoJUnitRunner // detect unused stubs @RunWith(MockitoJUnitRunner.class)
In the code below a UnnecessaryStubbingException in the last line is thrown and this line has to be removed to get the test green.
//code under test: ... String result = translator.translate("one") ... //test: ... when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized --> UnnecessaryStubbingException thrown
Keeps the Mockito 1 behavior. So no UnnecessaryStubbingException is thrown in the example above.
// don't detect, old behaviour @RunWith(MockitoJUnitRunner.Silent.class)
When migrating to Mockito 2 the strict runner may help you to detect a lot of unnecessary code in your tests - depending on the current test code quality. The strict runner checks all stubs if they are necessary for the test, if not an UnnecessaryStubbingException is thrown. It is recommend to use the strict runner and remove all the unused stubs in test, since it helps to minimize the amount of code and improves the readability. In huge projects with a lot of tests this might be bigger effort, especially when using abstract test classes. There it might be useful to use the silent runner. But keep in mind the strict runner showed you code smells and the migration effort for a Mockito 3 becomes much bigger.
Mockito matchers anyX() and any(SomeType.class) now reject nulls and check type.
//code under test: ... String result = executor.execute(null); ... //test: ... when(executor.execute(anyString())).thenReturn("SUCCESS"); // <- no argument of type string used, therefore 'execute' doesn't return "SUCCESS"
When migrating to Mockito 2 many tests may fail (depending on the quality of tests), because of this strict behavior of the any matchers. But this strict behavior shows code smells in your code, since there is a difference between null and a real object (e.g., null checks and therefore different execution path)
Recommendation:
In order to update Mockito it was necessary to update PowerMock as well. To avoid problems like this:
java.lang.NoClassDefFoundError: org/mockito/cglib/proxy/MethodInterceptor at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.<init>(PowerMockMaker.java:43) ... Caused by: java.lang.ClassNotFoundException: org.mockito.cglib.proxy.MethodInterceptor at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 40 more
Replace the api-mockito with api-mockito2.
Furthermore the powermock-api-mockito-common library is necessary.
-org.powermock:powermock-api-mockito = 1.7.0 +org.powermock:powermock-api-mockito2 = 1.7.0 +org.powermock:powermock-api-mockito-common = 1.7.0