Static method mocking
Performing unit testing with mock object is quite common. I’ve been used to do it with Easymock and sometimes JMock. However, in some cases, I had to face the issue where I wanted to mock the call to a static method. Of course, this could be due to a wrong design, but sometimes you don’t have much choice.
Using EasyMock or JMock, you can’t mock static method. But recently I found the project JMockit. JMockit depends on the JVM class redefinition mechanism exposed by java.lang.instrumentation to redefine specific method of a java class. Therefore, if you want to mock a static method, all you have to do is to create a mock class redefining the static method and to call Mockit.redefineMethods with the original class and the mock class as parameters.
Of course, since JMockit depends on the the JVM class redefinition mechanism, the units tests must be run with a JAVA 5 SE VM. Although the test code can still be compiled with a older compiler version.
In the following example, the method getDates of the ROCalParutionTitre class was calling the static method getAllDatesCalendrier of ROCalParutionDate class.
So I first create a mock class ROCalParutionDateMockit redefining the method getAllDatesCalendrier and during the unit test I used Mockit.redefineMethods(ROCalParutionDate.class, ROCalParutionDateMockit.class) to mock RoCalParutionDate class. To avoid troubles with the other tests, at the end of the unit test, I call Mockit.restoreAllOriginalDefinitions() to restore the normal situation.
The code below show a example where both EasyMock and JMockit are used to perform the unit testing.
public class ROCalParutionDateMockit {
public static ROCalParutionDate [] returnValue;
public static ROCalParutionDate[] getAllDatesCalendrier(ROCalParutionTitre titreCal) {
return returnValue;
}
}
public void testGetDates() throws NoSuchMethodException {
MockClassControl tC = MockClassControl.createControl(ROCalParutionTitre.class,
new Method[] { ROCalParutionTitre.class.getMethod(“getExactDate”,new Class[] { Timestamp.class }) } );
ROCalParutionTitre t = (ROCalParutionTitre) tC.getMock();
MockControl d1C = MockClassControl.createControl(ROCalParutionDate.class);
ROCalParutionDate d1 = (ROCalParutionDate) d1C.getMock();
MockControl d2C = MockClassControl.createControl(ROCalParutionDate.class);
ROCalParutionDate d2 = (ROCalParutionDate) d2C.getMock();
MockControl d3C = MockClassControl.createControl(ROCalParutionDate.class);
ROCalParutionDate d3 = (ROCalParutionDate) d3C.getMock();
ROCalParutionDate[] dateArray = {d1, d2, d3};
GregorianCalendar c = new GregorianCalendar(2006, 07, 01);
Timestamp t_from = new Timestamp(c.getTimeInMillis());
c.add(Calendar.DATE, 1);
Timestamp t1 = new Timestamp(c.getTimeInMillis());
c.add(Calendar.DATE, 1);
Timestamp t2 = new Timestamp(c.getTimeInMillis());
c.add(Calendar.DATE, 1);
Timestamp t3 = new Timestamp(c.getTimeInMillis());
c.add(Calendar.DATE, 1);
Timestamp t_to = new Timestamp(c.getTimeInMillis());
String freq = “L”;
ROCalParutionDateMockit.returnValue = dateArray;
Mockit.redefineMethods(ROCalParutionDate.class, ROCalParutionDateMockit.class);
d1.getDateTraiteDu();
d1C.setReturnValue(t1);
d1.getDateTraiteAu();
d1C.setReturnValue(t1);
d1.include(freq);
d1C.setReturnValue(false);
d2.getDateTraiteDu();
&nbs
p; d2C.setReturnValue(t2);
d2.getDateTraiteAu();
d2C.setReturnValue(t2);
d2.include(freq);
d2C.setReturnValue(true);
d3.getDateTraiteDu();
d3C.setReturnValue(t3);
d3.getDateTraiteAu();
d3C.setReturnValue(t3);
d3.include(freq);
d3C.setReturnValue(false);
d1C.replay();
d2C.replay();
d3C.replay();
ROCalParutionDate[] dates = t.getDates(t_from, t_to, freq);
assertNotNull(dates);
assertEquals(1, dates.length);
assertEquals(d2, dates[0]);
d1C.verify();
d2C.verify();
d3C.verify();
Mockit.restoreAllOriginalDefinitions();
}
Constructor mocking
As I was incresing my unit test coverage, I came to a situation where I wanted to mock the constructor of an object. Unfortunately, neither EasyMock, JMock nor JMockit could help me on that. Of course a better design (using a factory and interfaces in place of object) could have help me.
In this case, the only solution I could see is AOP. With AOP, you can intercept the constructor call and use an aspect to overwrite it. In fact, using AOP, you could almost do everything you want.