Tuesday, April 12, 2011

Mocking java System class and override System.currentTimeMillis() using JMockit

Recently i came across a very interesting problem while writing a system test for a component. The problem statement was to throw an operator event when the server's and client's system time is out of sync by some seconds. The system test needed to run on one box and still give different time for System.currentTimeMills()

To do this i used JMockit. Its fairly easy to get JMockit in your environment by mvn repo or by adding ivy settings in your project. Here is the repo that you can use to fetch JMockit using mvn

<repositories>
<repository>
<id>download.java.net</id>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories>

This is the library that you need to add as dependency for testing

<dependency>
<groupId>mockit</groupId>
<artifactId>jmockit</artifactId>
<version>0.993</version>
<scope>test</scope>
</dependency>

The other way of getting the jar is through adding this in your ivy.xml file

<dependency name="dspace-jmockit" rev="0.999.4" org="org.dspace.dependencies.jmockit"/>
Now comes the part of how you can override System.currentTimeMills
Below is the way you write the class be used to override the static methods of System

@MockClass(realClass = System.class)

public class MockSystem {

private int i = 0;


@Mock

public long currentTimeMillis() {

i++;

return i * 10000;

}

}


To use this in your test class you need to call this before you start the actual test.

Mockit.setUpMocks(new MockSystem());


Also you have to be careful to call this before your test ends so that you do not screw up any other test


Mockit.tearDownMocks(System.class);


A few things to be noticed here.
1. The overriding of System class static method can only be done if you are using JAVA 1.6. It will fail for lower versions.
2. If you get the following exception in your test then its because you are not initializing JMockit before you overrode its static method. To get rid of this you need to make sure that the Jmockit jar is above the junit jar in the export order of the libraries in your project.


INFO Caused by: java.lang.IllegalStateException: JMockit has not been initialized. Check that your Java 6 VM has been started with the -javaagent:/Users/rsingh/work/branches/enterprise-1/community/code/base/dependencies/lib/dspace-jmockit-0.999.4.jar command line option.

INFO at mockit.internal.startup.AgentInitialization.initializeAccordingToJDKVersion(AgentInitialization.java:44)

INFO at mockit.internal.startup.Startup.verifyInitialization(Startup.java:247)

INFO at mockit.Mockit.(Mockit.java:82)



No comments: