Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Mockito 2.x Over PowerMock Migration: Top 10 Tips and Tricks

DZone's Guide to

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.

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

After 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:

  1. Finally mocking final classes and methods.
  2. Support for Java 8.
  3. 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?

Image title

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.

Image title

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.

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
mockito ,unit tests ,java ,powermock

Published at DZone with permission of Hazem Saleh, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}