8
votes

I realize there are a lot of similar questions as this one, however after reading over most of them I seem to be having the same problem, but for different reasons.

I'm running a <junit> task inside my Ant build and am getting a ClassNotFoundException. In most of the similarly-related questions (such as the one above), this turned out to be various degrees of the author simply not configuring the JUnit classpath correctly. Although it may very well be the same for me, none of the suggestions to any of these other questions have worked for me.

My project directory structure:

MyProject/
    src/main/java/
        FakeObject.java
        ...the rest of my Java main source
    src/test/java
        FakeObjectUnitTest.java
        ...the rest of my Java test source
    bin/main
        FakeObject.class
        ...the rest of main Java binaries
    bin/test
        FakeObjectUnitTest.class
        ...the rest of main Java binaries
    lib/main
        ...my main dependencies
    lib/test
        junit-4.10.jar
        hamcrest-1.1.jar
        ...the rest of my test dependencies
    gen/reports
        ...where JUnit should be placing all test reports
    build/
        build.xml
        build.properties

In src/test/java/FakeObjectUnitTest.java:

// Package and imports omitted

public class FakeObjectUnitTest {
    @Test
    public void doSomething() {
        int x = 5;

        Assert.assertEquals(x, 5);
    }
}

My build.xml:

<project name="" basedir="..">
    <!-- Main classpath. -->
    <path id="main.class.path">
        <fileset dir="bin/main"/>
    </path>

    <!-- Test classpath. -->
    <path id="test.class.path">
        <fileset dir="bin/test"/>
    </path>

    <!-- JUnit classpath. -->
    <path id="junit.class.path">
        <fileset dir="lib/main" includes="*.jar"/>
        <fileset dir="lib/test" includes="*.jar"/>
        <path refid="main.class.path"/>
        <path refid="test.class.path"/>
    </path>

    <!--
        All previous targets omitted for brevity (such as for compiling, etc.), but
    I assure you all that they work and compile FakeObject.java/FakeObjectUnitTest.java into
    FakeObject.class/FakeObjectUnitTest.class respectively, and place them in the correct
bin directories.
    -->

    <target name="run-junit" depends="compile">

        <property name="junit.path" refid="junit.class.path"/>
        <echo message="JUnit ClassPath is: ${junit.path}"/>

        <junit printsummary="yes" haltonerror="yes" haltonfailure="yes">
            <classpath refid="junit.class.path"/>

            <formatter type="xml"/>

            <batchtest todir="gen/reports">
                <fileset dir="src/test/java">
                    <include name="**/*UnitTest*.java"/>
                </fileset>
            </batchtest>
        </junit>
    </target>
</project>

When I run this target from the command-line:

run-junit:
    [echo] Conducting unit tests with JUnit.
    [echo] JUnit ClassPath is: /<path-to-my-project>/MyProject/lib/test/hamcrest-1.1.jar:/<path-to-my-project>/MyProject/lib/test/junit-4.10.jar:/<path-to-my-project>/MyProject/bin/main/com/myproject/client/FakeObject.class:/<path-to-my-project>/MyProject/bin/test/com/myproject/client/FakeObjectUnitTest.class
    [junit] Running com.myproject.client.FakeObjectUnitTest
    [junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 0 sec

I do this to prove that it sees FakeObjectUnitTest.class on the JUnit classpath. However, it fails with an error. When I go into the XML TEST report for this test, I see the following:

<error message="com.myproject.client.FakeObjectUnitTest" type="java.lang.ClassNotFoundException">java.lang.ClassNotFoundException: com.myproject.client.FakeObjectUnitTest
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
</error>

When I run Ant in verbose mode (-v) the only hint I see are a bunch of warnings along the lines of:

Ignoring Exception java.util.zip.ZipException: error in opening zip file reading resource x

...where x is the name of a class file.

I found this question on SO, and the problem turned out to be that the author had added class files to the classpath, not JARs (which makes JUnit unhappy). So I tried removing main.class.path and test.class.path from junit.class/path and then I get an exception that none of the class files can be found.

Any ideas or thoughts as to what is going on? Thanks in advance, and sorry for the -v question here, but I figured the more details, the better.

3

3 Answers

7
votes

You need to use for package-like structures:
From the manual:

Wherever path-like values need to be specified, a nested element can be used. This takes the general form of:

    <classpath>
      <pathelement path="${classpath}"/>
      <pathelement location="lib/helper.jar"/>
    </classpath>

So your solution would look like:

<!-- JUnit classpath. -->
<path id="junit.class.path">
    <fileset dir="lib/main" includes="*.jar"/>
    <fileset dir="lib/test" includes="*.jar"/>
    <pathelement location="bin/main"/>
    <pathelement location="bin/test"/>
</path>
3
votes

Looking at your classpath:

...:/<path-to-my-project>/MyProject/bin/main/com/myproject/client/FakeObject.class:...

You can't put an individual class in the classpath like that. Instead, put the directory that's at the base of your package hierarchy in the classpath:

...:/<path-to-my-project>/MyProject/bin/main:...
0
votes

make modification in run-junit target as follows,

         <batchtest todir="gen/reports">
            <fileset dir="bin/tests">
                <include name="**/*UnitTest*.class"/>
            </fileset>
         </batchtest>