Java Development With Ant: JUnit

JUnit is the defacto standard Java unit testing framework.  This project consists of a number of unit tests for each of the components.  There are a couple interesting features in how this project uses JUnit:

The "test-module" target is a reusable target that each of the modules (or tiers) of the application use to run their unit tests.

    <target name="test-module">
<!-- Inputs: module, test.classpath -->
<echo level="info">Testing ${module}...</echo>
<mkdir dir="${test.dir}/data"/>
<propertycopy name="testcase" from="${module}-testcase" silent="true"/>
<copy todir="${test.dir}/${module}/classes">
<fileset dir="test/${module}" excludes="**/*.java"/>
</copy>
<junit printsummary="no"
errorProperty="test.failed"
failureProperty="test.failed"
fork="${junit.fork}">
<classpath>
<path refid="test.classpath"/>
<pathelement location="${build.dir}/${module}/classes"/>
<pathelement location="${test.dir}/${module}/classes"/>
<pathelement path="${java.class.path}"/>
</classpath>

<sysproperty key="docs.dir" file="${test.dir}/${module}/classes"/>
<sysproperty key="index.dir" file="${test.dir}/index"/>
<formatter type="xml"/>
<formatter type="brief" usefile="false"/>
<batchtest todir="${test.dir}/data" if="testcase">
<fileset dir="${test.dir}/${module}/classes"
includes="**/${testcase}.class"
/>
</batchtest>
<batchtest todir="${test.dir}/data" unless="testcase">
<fileset dir="${test.dir}/${module}/classes"
includes="**/*Test.class"
/>
</batchtest>
</junit>

<fail if="test.failed">Unit tests failed.</fail>
</target>

Because this is a reusable target, it is generic based on the module being passed to the target, and hence the classpath and output paths must use the ${module} property to keep things separate.  In order to have a module specific testcase isolation capability, the <propertycopy> task (from the Sourceforge ant-contrib project) is used to look up a dynamically named property.  For example, to run only the HtmlDocumentTest of the anttask module, set the Ant property anttask-testcase to be "HtmlDocumentTest" (i.e. run with -Danttask-testcase=HtmlDocumentTest, running the test-anttask target).

The <sysproperty> lines make Java system properties available to the test cases, allowing the tests, in this case, to have access to the test data files and Lucene index.

Writing output using the XML formatter allows for nice reporting later.  The brief formatter is used to display the results to the console.

The two <batchtest> sets (note one has an if attribute, and the other an 'unless' attribute) are mutually exclusive, and allow a single test case to be isolated and run independently, as described above with the HtmlDocumentTest example).