Mockito 2.x Over PowerMock Migration: Top 10 Tips and Tricks
With the long-awaited release of Mockito 2, we take a look at some tips to help smooth out your migration from 1.x to 2. You may need them.
Join the DZone community and get the full member experience.
Join For Freeafter so many years of hopeless waiting, mockito 2.x has been released to solve many problems that developers have had with their tests.
there are great features of mockito 2.x, such as:
- finally mocking final classes and methods.
- support for java 8.
- migration from cglib to bytebuddy.
but if you are having large tests written in mockito 1.x, will it be an easy task to migrate?
unfortunately, the migration most probably will be a painful task because mockito 2.x does not respect the old behavior of mockito 1.x. adding to this complexity, if you use powermock in your old tests, then you will have to face another dimension of complexity, as most of powermock’s versions have integration issues with mockito 2.x.
regarding powermock’s early issues with mockito 2.x, the powermock team announced that powermock 1.6.5 has experimental support for mockito 2.x but unfortunately, it was not that great.
in the beginning, when changing the mockito version to 2.x in your build.gradle file, you may find that more than 50% of your tests were failing: null pointer exceptions, compilation errors, no class definition found, unexpected thrown exception, …etc, and this is how you might look in the beginning of the migration.
do not panic and do not be sad, this artivle mentions some of the important challenges that you may face during the migration and tips to overcome these challenges to save your time.
1. use the proper powermock’s mockito api extension
using the
powermock-api-mockito
extension does not work with mockito 2.x. you will have the following exception when running your unit tests if you stick to the old extension:
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
in order to fix this issue, you should use the correct mockito api extension, which is:
powermock-api-mockito2
.
2. avoid using incompatible versions of mockito and powermock
always make sure to use compatible versions of mockito and powermock. for example, the following two versions are compatible:
- powermock version 1.7.0 rc2.
- mockito version 2.1.0.
3. say goodbye to mockito’s whitebox
mockito 2.x does not have whitebox anymore.
so what is the solution then?
initially, you can use powermock’s whitebox instead of the removed mockito 2.x whitebox. however, you need to know that this does not come without problems, such as this one that i reported to powermock:
org.powermock.reflect.exceptions.fieldnotfoundexception: no instance field
named xxx could be found in the class hierarchy
so if the initial solution does not work for you, consider writing your own. it's really not that hard.
4. using the right matchers
never forget to always use org.mockito.argumentmatchers instead of the old org.mockito.matchers.
for example, replace the old matcher imports:
import static org.mockito.matchers.any;
import static org.mockito.matchers.anyboolean;
import static org.mockito.matchers.anyint;
import static org.mockito.matchers.anystring;
import static org.mockito.matchers.eq;
with the following ones:
import static org.mockito.argumentmatchers.any;
import static org.mockito.argumentmatchers.anyboolean;
import static org.mockito.argumentmatchers.anyint;
import static org.mockito.argumentmatchers.anystring;
import static org.mockito.argumentmatchers.eq;
and so on with other matchers.
5. anyint() does not match long literals anymore
after the upgrade, you may find anyint() does not work because it cannot match long literals, such as 0l for example.
so in order to fix this issue, just replace anyint() with anylong() and you will be fine.
note : if you can match with the actual value instead of anyxxx(), this will be much better, as your test will have more transparency.
6. anystring() does not match null anymore
this can make a lot of tests fail, but anystring() does not include null anymore in mockito 2.x. this applies also to any(xxx). for example, any(inputstream.class) does not match null in mockito 2.x.
note : if you can match with the actual value instead of anyxxx(), this will be much better, as your test will have more transparency.
7. mockito 2.7.1 is not a real friend to powermock
unfortunately, if you use powermock 1.6.5 or even powermock 1.7.0rc2 with mockito 2.7.1 (the latest version at the time of writing this post), you will find the following exception with
donothing
:
java.lang.illegalaccesserror:
tried to access method
org.mockito.internal.stubbing.answers.doesnothing.<init>()v from
class org.powermock.api.mockito.powermockito
fortunately, this issue is fixed with powermock
1.7.0rc4
.
here's more information
.
so in summary, if you use mockito 2.7.1, do not forget to use powermock 1.7.0rc4.
8. original test exceptions are wrapped as runtimeexceptionproxy in mockito 2.x with powermock
unfortunately, as a workaround, you have to modify all the broken
@test(expected=someexception.class)
to
@test(expected=exception.class)
since the original exceptions are wrapped as mockito
runtimeexceptionproxy
in mockito 2.x with powermock.
this issue really requires further investigation to know why mockito 2.x does this wrapping with powermock. if you have a better solution for this, feel free to comment.
9. move away from powermock and depend on mockito 2.x only
try to create a plan to remove powermock by refactoring your app classes to be testable. mockito 2.x is really enough now.
10. review old tests
take this migration as a chance to review the old tests and to improve them in order to have more maintainable tests. this can help you strengthen your product code and allow easier refactoring for the current code base without surprises.
Published at DZone with permission of Hazem Saleh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments