Thursday Aug 27, 2009

Controlling the order of JUnit tests

Unit tests are small and independent, but today I was working on some functional tests that run though a series of steps (some using htmlunit which worked very well!).. most of the time the tests ran in the order they appeared in my code, but once I got enough tests a couple showed up out of order.  I didn't find a way to control the order individual @Test methods were run, but I did find that the JUnit Suite class provides control over the order separate test classes are run.  Example:

import org.junit.runners.Suite;
import mypkg.MyTests.*;

@RunWith(Suite.class)
@Suite.SuiteClasses({Group1.class, Group2.class, Group3.class})
public class MyTests {
  public class Group1 {
    //...
  }
  public class Group2 {
    //...
  }
//...
}

The order of tests within each group is not predictable, but the groups run in order.  To avoid listing all the inner classes in the @Suite.SuiteClasses annotation, I added this:

    public class SortedSuite extends Suite {
	public SortedSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
	    super(builder, klass, getSortedClasses(klass));
	}

	private static Class<?>[] getSortedClasses(Class<?> klass) throws InitializationError {
	    TreeSet<Class<?>> list = new TreeSet<Class<?>>(new Comparator<Class<?>>() {
		public int compare(Class<?> o1, Class<?> o2) {
		    return o1.getSimpleName().compareTo(o2.getSimpleName());
		}
	    });
	    for (Class<?> innerclass : klass.getClasses()) {
		if (Object.class.equals(innerclass.getSuperclass())) {
		    list.add(innerclass);
		}
	    }
	    return list.toArray(new Class<?>[0]);
	}
    }

This automatically finds the inner classes and sorts them by name.  It only adds classes that extend Object, to avoid adding some other classes I had used in my tests.  Now all it takes is @RunWith(SortedSuite.class).

Comments:

I changed the check for Object superclass to checking for the @Ignore annotation.. seems like a good fit for this annotation that JUnit already has. Replace the Object check with:
if (innerclass.getAnnotation(Ignore.class) == null) {

Posted by Alan on August 28, 2009 at 12:06 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed