Junit and Ant Overview

Junit and Ant are respectively Java standard unit testing framework and command-line tool, most of the time, we need to integrate them together for a project, in this tutorial I cover how to use Junit in ant task. To get started I assume you understand the basic knowledge and usages of Junit and Ant, otherwise please you may get first chance to read the manual (Junit tutorial and example).
First off, make sure you have a Java installed, then download ant library from (http://ant.apache.org/), uncompress the downloaded file into a directory, add ANT/BIN directory to ANT_HOME env variable.

We start writing Junit test case, for simplicity, we create a test case as following, it is a always passed case.

/**
 * This class is used to test runing junit in ant task.
 * Date: 2010-9-12
 * Time: 21:39:18
 */
import junit.framework.*;
public class JunitExample extends Assert {
    public void testMethod() {
        int a = 10;
        assertEquals(a, 10);
    }
}

We need to run this case from Ant command line rather than a IDE, so create a ANT build xml as showed below, there have several Ant targets, they take account in appropriate responsibility in this build procedure, target “init” prepares the all initiated parameters, target ‘compile’ depends on ‘init’ and is used to compile Java source codes.

Build.xml
<project name="JunitAntExample" default="test" basedir=".">
    <description>
        This class is used to test runing junit in ant task.
    </description>

    <property environment="env"/>
    <target name="init">
       <property name="main.src" value="src"/>
       <property name="build.dir" value="build"/>
       <property name="build.reports" value="build/report"/>
       <property name="build.classes" value="${build.dir}/classes"/>
       <property name="tests.lib" value="test"/>

       <property name="reports.dir" value="reports"/>

       <path id="test.cp">
       <filelist dir="${tests.lib}">
       <file name="junit.jar"/>
       </filelist>
       </path>
    </target>

    <target name="compile" depends="init">
       <mkdir dir="${build.classes}"/>
       <javac destdir="${build.classes}" debug="true" optimize="true" 
deprecation="false" failonerror="true">
       <src path="${main.src}"/>
       <classpath>
       <path refid="test.cp"/>
       </classpath>
       </javac>
    </target>

    <target name="test" depends="compile">
       <mkdir dir="${build.reports}"/>
       <junit fork="yes" forkmode="once" haltonfailure="no" showoutput="no" printsummary="yes">
         <formatter type="xml"/>
         <classpath>
            <pathelement location="${build.classes}"/>
            <path refid="test.cp"/>
         </classpath>
         <batchtest todir="${build.reports}">
            <fileset dir="src">
               <include name="JunitExample.java"/>
            </fileset>
          </batchtest>
       </junit>
       <junitreport todir="${build.reports}">
         <fileset dir="${build.reports}">
         <include name="TEST-*.xml"/>
           </fileset>
         <report format="frames" todir="${reports.dir}/junit_reports"/>
       </junitreport>
    </target>

   </project>

You may change junit library path to fit your environment, here is explanation and official document of attributes of Ant Target ‘Junit’:

fork Run the tests in a separate VM.
forkmode Controls how many Java Virtual Machines get created if you want to fork some tests. Possible values are “perTest” (the default), “perBatch” and “once”. “once” creates only a single Java VM for all tests while “perTest” creates a new VM for each TestCase class. “perBatch” creates a VM for each nested <batchtest> and one collecting all nested <test>s. Note that only tests with the same settings of filtertrace, haltonerror, haltonfailure, errorproperty and failureproperty can share a VM, so even if you set forkmode to “once”, Ant may have to create more than a single Java VM. This attribute is ignored for tests that don’t get forked into a new Java VM. since Ant 1.6.2
showoutput Send any output generated by tests to Ant’s logging system as well as to the formatters. By default only the formatters receive the output.
printsummary Print one-line statistics for each testcase. Can take the values on, off, and withOutAndErr. withOutAndErr is the same as on but also includes the output of the test as written to System.out and System.err.
batchtest A series of test class which need to run

The default target is set to ‘test’ in build XML, so from commend line, use command “ant” without target specified or “ant test” to run to run this task, this is output:

E:\apache\JunitAntExample>ant
Buildfile: build.xml

init:

compile:

test:
    [junit] Running JunitExample
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.1 sec
[junitreport] Processing E:\apache\JunitAntExample\build\report\TESTS-TestSuites.xml to C:\Users\ADMINI~1\AppData\Local\Temp\
null1758654992
[junitreport] Loading stylesheet jar:file:/D:/Program%20Files/apache-ant-1.7.1/lib/ant-junit.jar!/org/apache/tools/ant/taskde
fs/optional/junit/xsl/junit-frames.xsl
[junitreport] Transform time: 529ms
[junitreport] Deleting: C:\Users\ADMINI~1\AppData\Local\Temp\null1758654992

BUILD SUCCESSFUL

If plus ‘verbose’ on the end(“ant test -verbose”), more details are available:

E:\apache\JunitAntExample>ant test -verbose
Apache Ant version 1.7.1 compiled on June 27 2008
Buildfile: build.xml
Detected Java version: 1.5 in: C:\Program Files\Java\jdk1.5.0_22\jre
Detected OS: Windows Vista
parsing buildfile E:\apache\JunitAntExample\build.xml with URI = file:/E:/apache/JunitAntExample/build.xml
Project base dir set to: E:\apache\JunitAntExample
[antlib:org.apache.tools.ant] Could not load definitions from resource org/apache/tools/ant/antlib.xml. It could not be found
.
 [property] Loading Environment env.
Build sequence for target(s) `test' is [init, compile, test]
Complete build sequence is [init, compile, test, ]

init:

compile:
    [mkdir] Skipping E:\apache\JunitAntExample\build\classes because it already exists.
    [javac] JunitExample.java omitted as E:\apache\JunitAntExample\build\classes\JunitExample.class is up to date.

test:
    [mkdir] Skipping E:\apache\JunitAntExample\build\report because it already exists.
    [junit] Implicitly adding D:\Program Files\apache-ant-1.7.1\lib\ant-launcher.jar;D:\Program Files\apache-ant-1.7.1\lib\an
t.jar;D:\Program Files\apache-ant-1.7.1\lib\ant-junit.jar to CLASSPATH
    [junit] Executing 'C:\Program Files\Java\jdk1.5.0_22\jre\bin\java.exe' with arguments:
    [junit] '-classpath'
    [junit] 'E:\apache\JunitAntExample\build\classes;E:\apache\JunitAntExample\test\junit.jar;E:\apache\JunitAntExample;C:\Pr
ogram Files\Java\jdk1.5.0_22\lib;D:\Program Files\apache-ant-1.7.1\lib\ant-launcher.jar;D:\Program Files\apache-ant-1.7.1\lib
\ant.jar;D:\Program Files\apache-ant-1.7.1\lib\ant-junit.jar'
    [junit] 'org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner'
    [junit] 'JunitExample'
    [junit] 'filtertrace=true'
    [junit] 'haltOnError=false'
    [junit] 'haltOnFailure=false'
    [junit] 'formatter=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter'
    [junit] 'showoutput=false'
    [junit] 'outputtoformatters=true'
    [junit] 'logtestlistenerevents=true'
    [junit] 'formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,E:\apache\JunitAntExample\build\r
eport\TEST-JunitExample.xml'
    [junit] 'crashfile=E:\apache\JunitAntExample\junitvmwatcher6255708028101344995.properties'
    [junit] 'propsfile=E:\apache\JunitAntExample\junit6862956538265673645.properties'
    [junit]
    [junit] The ' characters around the executable and arguments are
    [junit] not part of the command.
    [junit] Running JunitExample
    [junit] junit.framework.TestListener: tests to run: 1
    [junit] junit.framework.TestListener: startTest(testMethod)
    [junit] junit.framework.TestListener: endTest(testMethod)
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.102 sec
[junitreport] Parsing file: 'E:\apache\JunitAntExample\build\report\TEST-JunitExample.xml'
[junitreport] Using class org.apache.tools.ant.taskdefs.optional.TraXLiaison
[junitreport] Processing E:\apache\JunitAntExample\build\report\TESTS-TestSuites.xml to C:\Users\ADMINI~1\AppData\Local\Temp\
null1200387502
[junitreport] Loading stylesheet jar:file:/D:/Program%20Files/apache-ant-1.7.1/lib/ant-junit.jar!/org/apache/tools/ant/taskde
fs/optional/junit/xsl/junit-frames.xsl
[junitreport] Transform time: 510ms

When reviewing the build file, You may ready noticed that the particular two lines <formatter type="xml"/> and <junitreport todir="${build.reports}"> exist in XML, this tells that reports are outputted to ${build.reports} and format is XML. Alternative, you can also ask for generating HTML reports.

  • The xml formatter element nested in the junit element produces raw data XML files.
  • The following junit report task generates a summary XML file named TESTS-TestSuites.xml
  • The report element nested in the junitreport task generates the final HTML and css files
  • The combination of the formatter plus the following batchtest task generates the pretty HTML reports.

I finally attached the screen shot of Junit html report, it is easy to quickly finger out whats cases pass/fail, for failures, stack track is provided.