colliedunk (4) [Avatar] Offline
#1
Hi there,
i'm trying to get this junit task to work in ant and keep getting this error:
Buildfile: build.xml

runTests:
     [echo] ...running our tests.
     [echo] ...remember to put junit.jar in ANT_HOME/lib directory.
    [junit] Running testContainer.TestGenericController$1
    [junit] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.02 sec
    [junit] Testsuite: testContainer.TestGenericController$1
    [junit] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.02 sec

    [junit] Testcase: warning took 0.01 sec
    [junit]     FAILED
    [junit] Class testContainer.TestGenericController$1 has no public constructo
r TestCase(String name) or TestCase()
    [junit] junit.framework.AssertionFailedError: Class testContainer.TestGeneri
cController$1 has no public constructor TestCase(String name) or TestCase()

The failure is very annoying and I am at my wits end. You see I can run the test inside eclipse by selecting Run As -> Junit Test Case, but get this failure when I run the test from the command line with ant. If someone could help me resolve this I would be very grateful. This is what the relevant parts of my build file looks like. Note that the src directory holds the source code, build dir is where the compiled classes are outputted to and lib is where junit.jar is stored:
<target name="runTests" description="Run junit tests." depends = "compile">
	<echo message="...running our tests."/>
	<echo message="...remember to put junit.jar in ANT_HOME/lib directory."/>
		
	<junit printsummary="yes" haltonfailure="yes">
		<classpath>
			<pathelement location = "${build}"/>
		</classpath>
			
		<batchtest fork="yes" todir="${docs}">
			<formatter type="plain" usefile = "false"/>
			<fileset dir="${build}" includes = "**/*Test*.class"/>
		</batchtest>

         </junit>
</target>

<!-- classpath used in the project -->
<path id = "projectClasspath">
	<pathelement location = "${lib}/junit.jar"/>
	<pathelement path = "${src}"/>
</path>
			

<target name="compile" description="Compile files and make javadocs." >
	<echo message="...compiling files"/>
	<javac srcdir="${src}" destdir="${build}">
		<classpath refid = "projectClasspath"/>
	</javac>
</target>


Here is the code:
/*
 * ErrorResponse class
 */
package myContainer;
/**
 * @author taylorjw
 */
public class ErrorResponse implements IResponse {
    private IRequest origionalReq;
    private Exception origionalExc;
    
    public ErrorResponse(IRequest req, Exception exc){
        this.origionalReq = req;
        this.origionalExc = exc;
    }
    
    public IRequest getOrigionalReq(){
        return this.origionalReq;
    }
    
    public Exception getOrigionalExc(){
        return this.origionalExc;
    }
    
}


/*
 * GenericController class
 */
package myContainer;
 import java.util.Map;
 import java.util.HashMap;

 
 /**
 *GenericController is a class that implements the Controller Design Pattern
 *@import java.util.Map;
 *@import java.util.HashMap;
  *@author taylorjw
  */
 public class GenericController implements IController{
 	
 	private Map reqHandlers = new HashMap();
 	
 	public IRequestHandler getHandler(IRequest req){
 	    if(!this.reqHandlers.containsKey(req.getName())){
 	        String message = "Cannot find handler for request nameed "+ "[" + req.getName() + "]";
 	        throw new RuntimeException(message);
 	    }
 	    return (IRequestHandler) this.reqHandlers.get(req.getName());
 	}
 	
 	public IResponse processRequest(IRequest req){
 	    IResponse res;
 	    try{
 	        res = getHandler(req).process(req);
 	    }catch (Exception e){
 	        res = new ErrorResponse(req, e);
 	    }
 	    return res;
 	}
 	
 	public void addHandler(IRequest req, IRequestHandler reqHand){
 	    if(this.reqHandlers.containsKey(req.getName())){
 	        throw new RuntimeException("A request handler has already been registered for request named "+ req.getName());
 	    }
 	    else{
 	        this.reqHandlers.put(req.getName(), reqHand);
 	    }
 	}
 	
 }

/*
 * IController Interface
 */
package myContainer;

/**
 *simple interface for a request object
 *@author James
 */

public interface IController{
	IResponse processRequest(IRequest req);
	void addHandler(IRequest req, IRequestHandler reqHand);
}

/*
 * IRequest Interface
 */
package myContainer;
/**
 *simple interface for a request object
 *@author James
 */
public interface IRequest{
	String getName();	
}

/**
 *simple RequestHandler interface
 */
package myContainer;


/**
 * @author taylorjw
 */
public interface IRequestHandler{
	IResponse process(IRequest req) throws Exception;
}

/**
 *simple response interface
 */
package myContainer;
/**
 * @author taylorjw
 */

 public interface IResponse{
 	
 }

And this is the test case:

/*
 * TestGenericController class
 */
package testContainer;

import myContainer.*;
import junit.framework.TestCase;

/**
 *@import myContainer.GenericController 
 *@import junit.framework.TestCase
 *@author taylorjw
 */
public class TestGenericController extends TestCase {
    private GenericController controller;
    /*
     *sets up resource used in test cases
     */
    protected void setUp() throws Exception {
        controller = new GenericController();
    }

    /**
     * test our addHandler method
     */
    public void testAddHandler(){
        IRequest req = new TestReq();
        IRequestHandler reqHandler = new TestHandler();
        controller.addHandler(req, reqHandler);
        IRequestHandler handler2 = controller.getHandler(req);
        
        assertSame(handler2, reqHandler);
    }
    
    
    /**
     * we set up test objects we will use in the testCases as
     * inner classes
     */
    private class TestReq implements IRequest{
        public String getName(){
            return "TestResponse";
        }
    }
    
    private class TestHandler implements IRequestHandler{
        public IResponse process(IRequest req) throws Exception{
            return new TestResponse();
        }
    }
      
    private class TestResponse implements IResponse{
             //empty class def
    }
}

ErikHatcher (211) [Avatar] Offline
#2
Re: junit task not working
My guess is that you need to upgrade your JUnit version to 3.8.1 or greater. Previous versions required the String-arg constructor. Your Eclipse environment is most likely using a more recent version of JUnit.
colliedunk (4) [Avatar] Offline
#3
Re: junit task not working
The version I am using is 3.8.1!
ErikHatcher (211) [Avatar] Offline
#4
Re: junit task not working
You should inquire with the Ant user e-mail list or with the JUnit e-mail list. Sorry that I'm not able to help further. It's not an Ant issue, I don't think.
colliedunk (4) [Avatar] Offline
#5
Re: junit task not working
Hi,
thanks for your reply but i have spotted the problem and my test run fine now, although it has confused me and I'm wondering if you would be so kind and clear the issue for me. I changed the build script to read:
<batchtest fork="yes" todir="${docs}">
        <formatter type="plain" usefile = "false"/>
	<fileset dir="${src}" includes = "**/*Test*.java"/>
</batchtest>

instead of:
<batchtest fork="yes" todir="${docs}">
        <formatter type="plain" usefile = "false"/>
	<fileset dir="${build}" includes = "**/*Test*.class"/>
</batchtest>


The problem seems to be that batchtest element wants the jave source files. This confuses me because they were compiled before this task was run-
<target name="runTests" description="Run junit tests." depends = "compile">


Would it be because the classpath element defined in this target just points to the compiled code directory ${build}?
<classpath>
	<pathelement location = "${build}"/>
</classpath>
steve_l (100) [Avatar] Offline
#6
Re: junit task not working
oh, this is a good one. Look at the message:

testContainer.TestGenericController$1

this isnt your TestGenericController class; its an inner class. Remember that java inner classes are turned into their own .class files, with a $ separated name.

So Ant's pattern *Test*.class matches TestGenericController$1 as well as your actual test classes. then the junit runner tried to instantiate the class and failed as it had no public constructor.


Your fix works because it is binding to the source files, not the generated classes. The other solution is to have a stricter pattern than *Test*.class. Usually I suffix tests with "Test" so can use "*Test.class", and not get inner classes.

Hope this helps,

-Steve Loughran.
ErikHatcher (211) [Avatar] Offline
#7
Re: junit task not working
Ah, good eye Steve! Sorry I missed that earlier. I rarely use inner classes, so I've not encountered this particular weirdness.
steve_l (100) [Avatar] Offline
#8
Re: junit task not working
well, junit itself doesnt help. it could have a better message, like "that inner class doesnt extend TestCase".

And ant could look at the classpath and verify that the class is also a testcase, the way <rmic> verifies that classes implement interfaces that extend Remote before handing them down to rmic.exe