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!
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 <code>true</code> 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); } } } }