Note: I'm using the term feature in the sense of map feature, not in the sense of application feature or implemented requirement.
A simple pattern for such tests is
public class FeatureTest
{
@Test
public void testAllFeatures()
{
for (Feature feature : findAllFeatures())
{
testOneFeature(feature);
}
}
private void testOneFeature(Feature feature)
{
// some logic with one or more JUnit assertions
}
}
Obviously, this naive approach has the following drawbacks:
- The test fails and terminates on the first incorrect feature. The remaining features will not be tested.
- All features get tested sequentially. This may take awfully long for a large database.
@RunWith(Parameterized.class)
public class FeatureTest
{
// This is the parameter for each instance of the test.
private Feature feature;
public FeatureTest(Feature feature)
{
this.feature = feature;
}
@Parameters
public static Collection<Object[]> getParameters()
{
List<Feature> features = findAllFeatures();
List<Object> parameters = new ArrayList<Object[]>(features.size());
for (Feature feature : features)
{
parameters.add(new Object[] { feature };
}
return parameters;
}
@Test
public void testOneFeature()
{
// assertions acting on the feature member
}
}
This solves the first problem: Each feature gets tested in its own test instance. Now if there is a large number of features or if each individual test is very expensive, we would like to run the test instances in parallel, using a thread pool, or maybe even a grid of multiple computers.
Browsing through the JUnit sources, I found a surprisingly easy way of parallelizing the tests with a thread pool, simply by using a custom runner:
@RunWith(Parallelized.class)
public class FeatureTest
{
// same class body as above
}
All you need is a simple extension of the Parameterized runner:
public class Parallelized extends Parameterized
{
private static class ThreadPoolScheduler implements RunnerScheduler
{
private ExecutorService executor;
public ThreadPoolScheduler()
{
String threads = System.getProperty("junit.parallel.threads", "16");
int numThreads = Integer.parseInt(threads);
executor = Executors.newFixedThreadPool(numThreads);
}
@Override
public void finished()
{
executor.shutdown();
try
{
executor.awaitTermination(10, TimeUnit.MINUTES);
}
catch (InterruptedException exc)
{
throw new RuntimeException(exc);
}
}
@Override
public void schedule(Runnable childStatement)
{
executor.submit(childStatement);
}
}
public Parallelized(Class klass) throws Throwable
{
super(klass);
setScheduler(new ThreadPoolScheduler());
}
}
The
RunnerScheduler interface is fairly new in JUnit and marked as experimental. I discovered it in the current version JUnit 4.8.1 and found it missing in JUnit 4.4.0 which we have been using so far. RunnerScheduler is also available in JUnit 4.7.0, but I did not check if this is the earliest version.




