3.15 Installing JUnit

3.15.1 Problem

You need to configure JUnit so you can run your tests using Ant. Although you have added junit.jar to your classpath, you still see errors.

3.15.2 Solution

You have three possible solutions:

  1. Install Ant's optional.jar as well as JUnit's junit.jar in the ANT_HOME/lib directory.

  2. Ensure that neither optional.jar nor junit.jar is in the ANT_HOME/lib directory. Then set up a classpath in your buildfile that includes both JAR files.

  3. Ensure that neither optional.jar nor junit.jar is in the ANT_HOME/lib directory. Then set your CLASSPATH environment variable to include both JAR files.

3.15.3 Discussion

Ant's junit task is implemented by a class named JUnitTask, which is found in the optional.jar file that ships with the Ant distribution. Ant includes many so-called "optional" tasks, which generally depend on external libraries in order to function. In the case of the junit task, junit.jar is required. It is your responsibility to download JUnit and properly configure it to work with Ant.

Class loading problems are common in cases where optional Ant tasks depend on external libraries such as junit.jar. The Java ClassLoader instance that loads the JUnitTask class must also be able to load various JUnit classes. For the proper classes to be visible, you must follow one of the three solutions that were just mentioned.

You generally install Ant's optional.jar in the ANT_HOME/lib directory, so the easiest way to configure JUnit is to also install junit.jar in ANT_HOME/lib. Example 3-6 shows an Ant buildfile with an "install.junit" target that automatically installs junit.jar for you. This target can be added to any of your buildfiles, thus ensuring that JUnit is properly configured to work with Ant.

Example 3-6. Installing JUnit
<project name="Java XP Cookbook" default="compile" basedir=".">
  <property name="dir.build" value="build"/>
  <property name="dir.src" value="src"/>
  <property environment="env"/>

  <path id="classpath.project">
    <pathelement path="${dir.build}"/>
  </path>

  <target name="install.junit">
    <fail unless="env.JUNIT_HOME">
      The JUNIT_HOME environment variable must be set.
    </fail>

    <available property="junit.already.installed"
               file="${ant.home}/lib/junit.jar"/>

    <copy file="${env.JUNIT_HOME}/junit.jar"
          todir="${ant.home}/lib"
          failonerror="true"/>
   
    <fail unless="junit.already.installed">
      junit.jar was not found in ANT_HOME/lib prior to this 
      build, so it was copied for you. Please try your build again.
    </fail>
  </target>

  <target name="prepare" depends="install.junit">
    <mkdir dir="${dir.build}"/>
  </target>

  ...remainder of buildfile omitted

Our target first ensures that the JUNIT_HOME environment variable is set. If it isn't, the build fails with an error message. Next, it sets an Ant property junit.already.installed if it finds that junit.jar is already present under ANT_HOME/lib.

After setting the property, our buildfile goes ahead and copies junit.jar from the JUnit directory to the Ant directory. If the file already exists, the copy operation does not do anything. If the copy fails, the build fails. The copy might fail, for example, if your JUNIT_HOME environment variable is set to some invalid directory.

Finally, our target fails the build if it finds that JUnit was not already installed before it performed the copy operation:

<fail unless="junit.already.installed">
  junit.jar was not found in ANT_HOME/lib prior to this 
  build, so it was copied for you. Please try your build again.
</fail>

You may wonder why we fail the build even though we just finished copying junit.jar to the ANT_HOME/lib directory. We have to abort the build because when the build first started, JUnit was not already installed. By this time the Ant class loader has already located all of the JAR files in ANT_HOME/lib, so we must start a new build in order for it to see junit.jar.

Another Technique

Here's another idea for configuring Ant and JUnit. Put ant.jar, optional.jar, and junit.jar in your project's lib directory, which is under version control so all developers see the same JAR files. Write your own ant.bat script and place it next to your buildfile. This custom ant.bat puts just the desired few jars on the classpath, does not include the user's environment classpath, and invokes Ant. Thus, there is no need to install Ant or JUnit on the development machine at all.

3.15.4 See Also

Recipe 3.8 shows how to define a classpath.