Changing the Order of your UnitTests
A few months ago we had a problem where Eclipse could not automatically run all jUnit unit tests in a package if that package references a class called "enum", which is a reserved word in Java 1.6. I'll spare you the details, but we were forced to create a TestSuite. Normally we avoid this construction because it's easy to create a new unit test and forget to add it to the correct TestSuit. So as a workaround we wrote some code which could build and return a TestSuite dynamically. Right-click in eclipse, select "Run as Unittest", sit back and enjoy.
Lately this piece of code came in handy while testing another application, which required the removal of data from a database. Yes I know, Unittests should maybe not depend on databases because it leans towards integration testing, but here we are, and I need to solve it. I used the old TestSuite code and changed it so that the TestCase I needed to run first was singled out, while still maintaining the functionality of auto-detecting testcases in the source folder.
I've cleaned up the code and made an example implementation which sorts the test cases in alpabetical order. It's a simple starting point and definetely not the prettiest code I've ever written but it works, it helped me and it might help you. Copy/paste, and adjust to your own needs.Have fun!
[sourcecode language="java" toolbar="false" wraplines="true" padlinenumbers="true" gutter="false" autolinks="false"] package com.rolfje.example;
import java.io.File; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List;
import junit.framework.Test; import junit.framework.TestSuite;
/**
- Constructs a testsuite by dynamically scanning for
- classes ending in "*Test", and allows for re-ordering of
- the Classes in the Suite. */ public class OrderedTestSuite {
public static Test suite() throws Exception {
// Find all test classes
List testClasses = findTestClasses();
// Custom test ordering example: Sort test classes in
// natural alphabetic order based on simple classname
Collections.sort(testClasses, new Comparator() {
@Override
public int compare(Class o1, Class o2) {
return o1.getSimpleName().compareTo(
o2.getSimpleName());
}
});
// Convert the Set to a TestSuite
TestSuite suite = new TestSuite(
"Custom ordered TestSuite");
for (Class testClass : testClasses) {
suite.addTestSuite(testClass);
}
return suite;
}
private static List findTestClasses() throws Exception { List testClasses = new ArrayList();
File testDir = getRootOfTestTree();
List files = new ArrayList();
getTestFiles(files, testDir);
int nameIdx = testDir.getAbsolutePath().length() + 1;
for (Iterator iterator = files.iterator(); iterator
.hasNext();) {
File file = (File) iterator.next();
String className = file.getAbsolutePath().substring(
nameIdx);
className = className
.replace(File.separatorChar, '.');
className = className.replaceAll(".class", "");
Class testClass = Class.forName(className);
// Prevent recursion
if (OrderedTestSuite.class.equals(testClass)) {
continue;
}
if (isTestClass(testClass)) {
testClasses.add(testClass);
}
}
return testClasses;
}
/** *
- @param clazz Class to check
- @return
true
if the given Class is a -
usable implementation of {@link Test}
*/ private static boolean isTestClass(Class clazz) throws Exception { int modifiers = clazz.getModifiers(); if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) || Modifier.isPrivate(modifiers)) { return false; }
return Test.class.isInstance(clazz.newInstance());
}
/**
- @return The root directory of the Java Test sources. */ private static File getRootOfTestTree() { String meAsClasspathResource = OrderedTestSuite.class .getResource( OrderedTestSuite.class.getSimpleName() + ".class").getFile() .replace('/', File.separatorChar); String myLocation = OrderedTestSuite.class .getCanonicalName(); myLocation = myLocation .replace('.', File.separatorChar);
if (meAsClasspathResource == null
|| !meAsClasspathResource.contains(myLocation)) {
throw new RuntimeException(
"Can not find the class resource for "
+ OrderedTestSuite.class.getCanonicalName());
}
meAsClasspathResource = meAsClasspathResource
.substring(0,
meAsClasspathResource.indexOf(myLocation));
File dir = new File(meAsClasspathResource);
if (!dir.exists()) {
throw new RuntimeException("The directory "
+ dir.getAbsolutePath() + " does not exist.");
}
if (!dir.isDirectory()) {
throw new RuntimeException(dir.getAbsolutePath()
+ " is not a directory.");
}
return dir;
}
/**
- Recursively iterates through the nextFiles array to
- find all test files. which it subsequently returns.
- @param allTestFilesSoFar
-
new Files will be added to this List
- @param nextDir
-
The directory to scan for java Test files
*/ private static void getTestFiles( List allTestFilesSoFar, File nextDir) { File[] files = nextDir.listFiles(); for (int t = 0; t < files.length; t++) { File nextFile = files[t]; if (nextFile.isDirectory()) { getTestFiles(allTestFilesSoFar, nextFile); } else if (nextFile.getName().endsWith("Test.class") || nextFile.getName().endsWith("Suite.class")) { allTestFilesSoFar.add(nextFile); } } } } [/sourcecode]