Stubbing Java Classes
by Sebastien Mirolo on Wed, 7 Sep 2011Many times while validating a software product, you have to substitute a few parts in order to enable automated testing. This was again the case recently when I was confronted with a java application built as a jar file. The application relied on a complex subsystem of components that needed to be stubbed out in the test runner.
A common approach is to create an interface and two implementation classes, the production one and the test runner stub, then build the jar in "release" and "debug" mode, embedding the appropriate implementation in the jar. It works but has the nasty side-effects of having two different jars for "release" and "debug". We can do better than that through the java class loading mechanism. The idea is to build a single (release) jar and put the test runner stubs earlier in the class loading path. That is how we do it. Create three source files as follow:
release/Main.java:
class Main { public static void main( String[] args ) { Override o = new Override(); o.chachacha(); } }
release/Override.java:
class Override { public void chachacha() { System.out.println("Release class overriden...\n"); } }
release/manifest.txt:
Main-Class: Main
testRunner/Override.java:
class Override { public void chachacha() { System.out.println("TestRunner class override...\n"); } }
We then build a jar that contains the release classes.
$ pushd release $ javac Main.java $ jar cfm ../release.jar manifest.txt *.class $ popd
Following we compile the test runner override.
$ pushd testRunner $ javac -d .. Override.java $ popd
Time for testing ...
$ java -cp . -jar release.jar Release class overriden...
That did not work but the following did.
$ java -cp .:release.jar Main TestRunner class override...