Mock Objects with EasyMock and JMockit

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. 

Genetic algorithms and Java

Recently I had to quickly find a way to find the best gaussian curve fitting a set of data. After having search on the web for a specific algorithm, I end up with the JGAP project.

The JGAP project offers a library to easily create an application using a genetic algorithm. Since genetic algorithm can be used to solve regression problems, I decide to make a test with JGAP.

The JGAP project has a very clear API, with true “genetician” vocabulary. In less that 2 hours, I had my curve fitting application. I still have some convergence issues when the number of samples become high but I’m confident in the result.

instanceof and Hibernate lazy collection

I discovered the Proxy Visitor Pattern after having encountered the “proxy problem”.

In short, the “proxy problem” occurs when you want to cast or test the class of an instance coming from a lazy loaded polymorphic collection. By polymorphic collection, I mean a hibernate collection containing instances of polymorphic object.

Because of the lazy loading process, the true instance are replaced by proxies, therefore the instanceof does not work.

Luckily, The Proxy Visitor Pattern proposes a solution to this issue.

However, recently I had to extend this pattern. I needed the reference of the true instance to pass it as a parameter to another method. Because of the proxy, I couldn’t cast the collection instance. I create a Visitor as followed:

public class VisitorImpl implements Visitor {
public static final int FORM_FIELD = 1;
public static final int FORM_BLOCK = 2;
protected FormElement lastChecked;
protected boolean lastCheckedTrace = 0;
public boolean isFormField() {
return (lastCheckedTrace & FORM_FIELD) != 0;
}
public boolean isFormBlock() {
return (lastCheckedTrace & FORM_BLOCK) != 0;
}
public FormElement getLastChecked() {
return lastChecked;
}
public void visit(FormField field) {
lastChecked = field;
lastCheckedTrace = FORM_FIELD;
}
public void visit(FormBlock block) {
lastChecked = block;
lastCheckedTrace = FORM_BLOCK;
}
}

I can check the type of the collection instance proceeding as followed:

...
Visitor checker = new Visitor();
for (Object tabElObj : tab.getFormElements()) {
FormElement element = (FormElement) tabElObj;
//Is the element a form field
element.accept(visitor);
if (visitor.isFormField())
{
// do something with (FormField) visitor.getLastChecked() ...
}
}
...

Art of Illusion

I just discover a very nice Java application: Art Of Illusion

This is a full 3D modeling and animation tool fully written in Java.

I took some time to make some tests and you can see the result below (pretty cool …)

hourglass

 

Ant, MaxQ and CruiseControl Integration

It took me a whole day but I did it. I wanted to integration MaxQ testing within a CruiseControl automatic build process.

Step 1 – Integrate application deployment in the build process

First of all, I had to deploy automatically the web application on Tomcat. Based on the work of Matt Raible (thanks Matt), I first defined a tomcatTask.properties file defined as follow:

deploy=org.apache.catalina.ant.DeployTask
install=org.apache.catalina.ant.InstallTask
list=org.apache.catalina.ant.ListTask
reload=org.apache.catalina.ant.ReloadTask
remove=org.apache.catalina.ant.RemoveTask
resources=org.apache.catalina.ant.ResourcesTask
roles=org.apache.catalina.ant.RolesTask
start=org.apache.catalina.ant.StartTask
stop=org.apache.catalina.ant.StopTask
undeploy=org.apache.catalina.ant.UndeployTask

Then I defined the task in the build.xml file:

<taskdef file="tomcatTasks.properties">
<classpath>
<pathelement path="${tomcat.home}/server/lib/catalina-ant.jar"/>
</classpath>
</taskdef>

Deploying a war is done using:

<target name="deploy-war" description="Deploy the war file on tomcat server">
<echo>+---------------------------------------------------+</echo>
<echo>|                                                   |</echo>
<echo>| DEPLOYING APPLICATION                             |</echo>
<echo>|                                                   |</echo>
<echo>+---------------------------------------------------+</echo>
<deploy url="${tomcat.manager.url}"
username="${tomcat.username}"
password="${tomcat.password}"
path="/${webapp.name}"
war="file:${build.dir}/war/bomdb.war"/>
<sleep minutes="1" />
</target>

The sleep of 1 minute is there only to be sure to start the tests after the application is fully initialized. It may be not necessary but on my build machine (quite old) it was.

Undeploying the war is done through:

<target name="undeploy-war" description="Undeploy the war file">
<echo>+---------------------------------------------------+</echo>
<echo>|                                                   |</echo>
<echo>| UNDEPLOY INTEGRATION TESTS                        |</echo>
<echo>|                                                   |</echo>
<echo>+---------------------------------------------------+</echo>
<undeploy url="${tomcat.manager.url}"
username="${tomcat.username}"
password="${tomcat.password}"
path="/${webapp.name}"/>
</target>
Step 2 – integrating MaxQ and Ant

Looking at the MaxQ API, I found a ant task and try to implement it. I created a jar and defined a task in the build.xml by defining a new task:

<taskdef name="maxq"
classname="com.dfs.ant.taskdefs.optional.maxq.MaxqTask">
<classpath id="maxq.classpath">
<pathelement location="${lib.build.dir}/maxq.jar" />
<pathelement location="${lib.build.dir}/maxq-ant.jar" />
<pathelement location="${lib.build.dir}/junit-3.8.1.jar" />
<pathelement location="${ant.home}/lib/ant-junit.jar" />
<fileset dir="${maxq.dir}/lib">
<include name="*.jar"/>
</fileset>
<pathelement location="${lib.build.dir}/jython.jar" />
<pathelement location="${lib.dir}/commons-logging.jar" />
</classpath>
</taskdef>

the ${maxq.dir} defines the directory where maxq was installed.

It took me a while before being able to run the test scripts properly. With the ant task as it is in the CVS, I had some trouble with the script file name and the fact that I was not starting the tests from the root directory of the test scripts. So, I made some updates to the classes.

To launch the tests, I just add the following to the build file:

<delete dir="${inttest.xml.dir}"/>
<mkdir dir="${inttest.xml.dir}"/>
<maxq errorProperty="inttest.failed"
failureProperty="inttest.failed"
maxDir="${maxq.dir}"
fork="no"
>
<classpath>
<pathelement path="${inttest.xml.dir}" />
</classpath>
<formatter classname="com.dfs.ant.taskdefs.optional.maxq.SummaryMaxqResultFormatter" usefile="false" />
<formatter type="xml" />
<batchtest todir="${inttest.xml.dir}" pythonPath="${jython.lib}">
<fileset dir="${maxq.test.src.dir}">
<include name="**/*.py" />
</fileset>
</batchtest>
</maxq>

The <formatter> tags are just there because this part was integrated in a CruiseControl process.

So this is it!!

The only problem that left is the fact that making regular deploy/undeploy on the build machine seems to be highly memory consuming or that there is a memory leak somewhere. Whatever, it seems that I have to restart the tomcat server regulary.

Any idea to avoid that?