This post originated from an RSS feed registered with Agile Buzz
by Marty Andrews.
Original Post: A faster alternative to batchtest with JUnit in Ant
Feed Title: Ramblings of the Wry Tradesman
Feed URL: http://www.wrytradesman.com/blog/index.rdf
Feed Description: Marty Andrews talks about the day to day issues he faces as an agile coach on large enterprise applications in Australia.
Want faster Ant build times? One of the most common culprits I've seen for slow builds is the use of
batchtest under the junit task while it has fork="yes"
set.
People end up in this state for a variety of reasons. The batchtest example in
the Ant docs has fork="yes" set. So does the example in the cruise
control docs. Perhaps they started not forking a VM, but got clashes with XML (or other)
libraries, and that was the easiest fix. Whatever the reason, I've seen lots of people do it,
and there is a better way.
Lets start with a typical example. Here's what your Ant test target might look like to start off
with:
The basic approach is to convert this Ant script which runs lots of tests into an Ant script
that runs only one test. Several things need to happen though. Firstly, the virtual machine
still needs to be forked, to make sure classpath issues are not re-introduced. Secondly, the
test has to become a suite so that all of the tests will still be run. Finally, some sort of
filter mechanism needs to be put into the suite that matches the fileset filtering mechanism
in the batchtest
The Ant script now becomes a bit simpler. The batchtest section is gone, and
a single test name is in its place: com.thoughtworks.todolist.AllTests.
To get the test suite to work as per batchtest, I use a utility from the
JUnit Addons project. It
dynamically builds up a test suite from a directory structure with custom filters to
include or exclude classes. My test suite looks like this:
package com.thoughtworks.todolist;
import junit.framework.Test;
import junitx.util.DirectorySuiteBuilder;
import junitx.util.SimpleTestFilter;
public class AllTests {
public static Test suite() throws Exception {
DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
builder.setFilter(new SimpleTestFilter() {
public boolean include(Class clazz) {
return super.include(clazz) &&
!getPackageName(clazz).equals("com.thoughtworks.todolist.acceptance");
}
});
return builder.suite("build/test/classes");
}
}
The use of the DirectorySuiteBuilder class replaces the batchtest
component of the Ant build script, and the use of the SimpleTestFilter replaces
the need for the nested fileset element.
That's all there is to it. In my simple application that so far has a grand total of 11 unit
tests, I managed to cut my build time from 4 seconds down to 2 seconds. Phew! Pretty quick huh?
Well - maybe in my case it didn't matter so much, but I've seen this cut minutes of builds for
"real" projects before. Let me know how it goes for you.
Oh yeah - as an added bonus, you now have a stand-alone JUnit test suite that will always be
up to date with all of your unit tests. It has no dependancy on Ant, so you can run it by itself
inside your IDE (or whatever environment you use for JUnit tests).