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]