A short introduction
Nowadays it is pretty difficult to write self-contained unit tests for JEE applications. This is due to the fact that managed beans usually interact with the container in which they run and have a certain context at runtime. Two examples would be the usage of @Inject
to inject dependencies and retrieving the JSF FacesContext via the static call to FacesContext.getCurrentInstance()
. In both cases, trying to use a dependency or the context, would end in a NullPointerException
.
One way to fix this problem is to use a framework like Arquillian to actually deploy the unit tests and run them within a real container. But in this case it is more likely to write tests, which don’t test just a single method, or class, but a complete module with all dependencies. What we need is to a way to be able to abstract from everything we don’t want to test explicitly. This leads us to a mocking framework.
There are several mocking frameworks, namely EasyMock, Mockito, JMockit amongst others. A common combination is Mockito and PowerMock, because Mockito doesn’t allow certain things like mocking private
, static
or final
methods. With PowerMock this is possible, but it depends on Javassist which does the bytecode manipulation to make this magic possible. This leads us to the actual problem described below: the latest version of Javassist is not compatible with Java 7.
How to get PowerMock running
I assume that we have a maven project, the test dependencies might look like this:
<dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit-dep</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.5.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.5.1</version> <scope>test</scope> </dependency>
Let’s try a minimal test mocking the static FacesContext
:
@RunWith(PowerMockRunner.class) @PrepareForTest({FacesContext.class}) public class MockingTest { @Before public void mockFacesContext() { PowerMockito.mockStatic(FacesContext.class); mockFacesContext = mock(FacesContext.class); when(FacesContext.getCurrentInstance()).thenReturn(mockFacesContext); } }
When we try to run a test in eclipse and use a Java 7 version to do so, we will end up with an error like the following:
java.lang.VerifyError: Inconsistent stackmap frames at branch target 40 in method your.package.YourTest.()V at offset 26 at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Unknown Source) at java.lang.Class.privateGetPublicMethods(Unknown Source) at java.lang.Class.getMethods(Unknown Source) ...
This is due to the fact that with Java 7 the new StackMap Frames, which were introduced already with Java 6, are not optional anymore, but default. But they can be disabled via the (non-standard) JVM option: -XX:-UseSplitVerifier
, which will then fallback to the Java 6 behaviour. Thus our unit tests will now run and we can use all of PowerMockito’s features.
When running the tests from within eclipse, we need to configure the following:
Run -> Run Configurations -> JUnit -> <select your profile> -> Arguments -> VM arguments -> add -XX:-UseSplitVerifier
When using maven, we need to add it to our test plugin as well:
<pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.14.1</version> <configuration> <argLine>-XX:-UseSplitVerifier</argLine> </configuration> </plugin> </plugins> </pluginManagement>