Saturday, December 30, 2006

JUnit in Ant Classpath Hell

Running JUnit tests from an Ant build script - piece of cake? Welcome to Classpath Hell. Read the Ant FAQ for a taste of what to expect... (NOTE: Ant 1.7, which just came up, finally "solves" this, but most project are on Ant v1.6.5 not 1.7 yet.)

Essentially, you have to either add the junit.jar to your global CLASSPATH system environment variable (very bad) or copy junit.jar to your %ANT_HOME%/lib or remove ant-junit.jar from %ANT_HOME%/lib (and have both ant-junit.jar and junit.jar in your project and then use an ant taskdef with classpath) - bad too.

The best I could think of to make this less painful is at least have a build script semi-transparently take care of this, by itself automatically copying a junit.jar to your %HOME%/.ant/lib (slightly better than %ANT_HOME%/lib probably) if it is not there yet... not perfect, as the build of a project thus "pollutes" a globally installed application - but apparently the best you can do?

Such an ant build script would look like this:

<target name="copyJUnitToAntClasspathIfNeeded" unless="isJUnitInAntClasspath">
<fail unless="ant.library.dir" message="The ant variable ant.library.dir is not available... that's weired. Please manually copy lib/junit.jar into the lib directory of where you installed ant">

<copy file="lib/junit-3.8.1.jar" todir="${user.home}/.ant/lib" verbose="true" /> <!-- Or ${ant.library.dir}, but user.home is probably better? -->

<echo message="JUnit.jar had to be copied into the lib directory of your ant" />
<echo message="installation. Please manually restart the build now." />
<echo message="(There is unfortunately no cleaner way to do this prior to Ant 1.7; see: " />
<echo message="http://ant.apache.org/faq.html#delegating-classloader)" />
<fail message="Please just launch this build once again, this is a one-time only behaviour." />
</target>

<target name="testIfJUnitInAntClasspath">
<available property="isJUnitInAntClasspath" classname="junit.framework.Test" />
<antcall target="copyJUnitToAntClasspathIfNeeded"/>
</target>

<target name="test" depends="testIfJUnitInAntClasspath">
<junit ... />

Labels: