How do I run JUnit tests during my Ant build script while omitting test classes from my resulting jar?

17,177

Solution 1

Based on @Jon's advice I changed the junit target to run against the build/classes folder instead of the jar and updated the dependencies appropriately.

My updated build.xml file is below:

<project name="HelloWorld" basedir="." default="main">

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

    <property name="build.dir"   value="build"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir"     value="${build.dir}/jar"/>
    <property name="lib.dir"     value="lib"/>
    <property name="report.dir"  value="${build.dir}/junitreport"/>

    <property name="main-class"  value="oata.HelloWorld"/>

    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar"/>
        <path location="[LocalPath]/junit-4.8.2.jar"/>
    </path>

    <path id="application" location="${jar.dir}/${ant.project.name}.jar"/>

    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>

    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
        <copy todir="${classes.dir}">
            <fileset dir="${src.dir}" excludes="**/*.java"/>
        </copy>
    </target>

    <target name="jar" depends="junit">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" excludes="**/*Test.class">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
            </manifest>
        </jar>
    </target>

    <target name="junit" depends="compile">
        <mkdir dir="${report.dir}"/>
        <junit printsummary="yes" haltonfailure="yes" showoutput="yes">
            <classpath>
                <path refid="classpath"/>
                <path location="${classes.dir}"/>
            </classpath>

            <formatter type="xml"/>

            <batchtest fork="yes">
                <fileset dir="${src.dir}" includes="*Test.java"/>
            </batchtest>
        </junit>
    </target>

    <target name="junitreport" depends="junit">
        <junitreport todir="${report.dir}">
            <fileset dir="${report.dir}" includes="TEST-*.xml"/>
            <report todir="${report.dir}"/>
        </junitreport>
    </target>

    <target name="run" depends="jar">
        <java fork="true" classname="${main-class}">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>
        </java>
    </target>

    <target name="clean-build" depends="clean,jar"/>

    <target name="main" depends="clean,run"/>

</project>

Solution 2

Can you change:

<target name="jar" depends="compile">
    <mkdir dir="${jar.dir}"/>
    <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
        <manifest>
            <attribute name="Main-Class" value="${main-class}"/>
        </manifest>
    </jar>
</target>

to:

<target name="jar" depends="junit">
    <mkdir dir="${jar.dir}"/>
    <jar destfile="${jar.dir}/${ant.project.name}.jar">
        <fileset dir="${classes.dir}" excludes="**/*Test.class"/>
        <manifest>
            <attribute name="Main-Class" value="${main-class}"/>
        </manifest>
    </jar>
</target>

 <target name="junit" depends="compile">
     <mkdir dir="${report.dir}"/>
     <junit printsummary="yes" haltonfailure="yes" showoutput="yes">
        <classpath>
            <path refid="classpath"/>
            <path refid="application"/>
        </classpath>

        <formatter type="xml"/>

        <batchtest fork="yes">
            <fileset dir="${src.dir}" includes="*Test.java"/>
        </batchtest>
    </junit>
</target>

That should exclude the Test classes I believe from the final JAR file.

n.b The change in dependencies for each of the tasks.

Share:
17,177
Redwood
Author by

Redwood

I'm a San Francisco Bay Area programmer working in Objective-C/Cocoa and C#/.NET.

Updated on June 04, 2022

Comments

  • Redwood
    Redwood almost 2 years

    I'm using the Hello World with Ant tutorial from the Ant manual to learn about Ant.

    The last part of the tutorial involves adding JUnit tests to the project.

    I've got everything working as described in the tutorial and am now going on to make some minor changes.

    One of the changes I would like to make is to run the tests during a typical build but not have the *Test.class files end up in the final .jar file for the application. This is because the eventual project I will be working on will be for a device with limited hard drive space and support for only a subset of the Java SDK so I would prefer to just omit these test files entirely from the jar.

    How do I do this?

    It would be easy enough to create two separate jars, one for testing and one for deployment, but this seems less than ideal.

    My current build.xml file is below.

    <property name="src.dir"     value="src"/>
    
    <property name="build.dir"   value="build"/>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir"     value="${build.dir}/jar"/>
    <property name="lib.dir"     value="lib"/>
    <property name="report.dir"  value="${build.dir}/junitreport"/>
    
    
    <property name="main-class"  value="oata.HelloWorld"/>
    
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar"/>
        <path location="[LocalPath]/junit-4.8.2.jar"/>
    </path>
    
    <path id="application" location="${jar.dir}/${ant.project.name}.jar"/>
    
    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>
    
    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
        <copy todir="${classes.dir}">
            <fileset dir="${src.dir}" excludes="**/*.java"/>
        </copy>
    </target>
    
    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
            </manifest>
        </jar>
    </target>
    
     <target name="junit" depends="jar">
         <mkdir dir="${report.dir}"/>
         <junit printsummary="yes" haltonfailure="yes" showoutput="yes">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>
    
            <formatter type="xml"/>
    
            <batchtest fork="yes">
                <fileset dir="${src.dir}" includes="*Test.java"/>
            </batchtest>
        </junit>
    </target>
    
    <target name="junitreport" depends="junit">
        <junitreport todir="${report.dir}">
            <fileset dir="${report.dir}" includes="TEST-*.xml"/>
            <report todir="${report.dir}"/>
        </junitreport>
    </target>
    
    <target name="run" depends="junit">
        <java fork="true" classname="${main-class}">
            <classpath>
                <path refid="classpath"/>
                <path refid="application"/>
            </classpath>
        </java>
    </target>
    
    <target name="clean-build" depends="clean,junit"/>
    
    <target name="main" depends="clean,run"/>
    

    One thing I have tried is modifying the jar command to exclude the *Test.class files

    ...
    <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" excludes="**/*Test.class">
    ...
    

    which successfully excludes the test classes but then when the tests are run via the junit target it fails with the following stack trace when run with -v:

    [LocalPath]\build.xml:44: Test HelloWorldTest failed
            at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.actOnTestResult(JUnitTask.java:1863)
            at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:814)
            at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.executeOrQueue(JUnitTask.java:1808)
            at org.apache.tools.ant.taskdefs.optional.junit.JUnitTask.execute(JUnitTask.java:760)
            at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
            at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
            at org.apache.tools.ant.Task.perform(Task.java:348)
            at org.apache.tools.ant.Target.execute(Target.java:390)
            at org.apache.tools.ant.Target.performTasks(Target.java:411)
            at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1397)
            at org.apache.tools.ant.Project.executeTarget(Project.java:1366)
            at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
            at org.apache.tools.ant.Project.executeTargets(Project.java:1249)
            at org.apache.tools.ant.Main.runBuild(Main.java:801)
            at org.apache.tools.ant.Main.startAnt(Main.java:218)
            at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
            at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
    
  • Redwood
    Redwood over 13 years
    That does not work to exclude the test files from my .jar, even after adding the missing asterisk (**/*Test.class). I edited my original post with something similar that I've tried.
  • Jonathan Holloway
    Jonathan Holloway over 13 years
    See the above on changing the depends attributes on the tasks.