Eclipse: Running all JUnit tests at once

by Stefan

When developing test driven it is essential to be able to run all existing unit tests over and over again as fast as possible. When the application gets larger the natural way to modularize is to distribute the code among multiple projects. I am not aware of tooling that ships with Eclipse and that allows you to run all JUnit tests based on a multi-project selection or on a selected working set.

I’ve used several workarounds in the past (Ant script, TestSuites, Maven build), but none was really satisfying. I recently stumbled upon the ClassPathSuite by Johannes Link which offers exactly what I was looking for. The library internally scans the classpath for classes with JUnit4 annotated methods and then executes all found tests. Sounds simple. This classpath-based solution also has the advantage that any Eclipse classpath container can be used so this works with OSGi-based bundles as well as with Maven projects, for instance.

Setup a ClassPathSuite test project

All you need to do is to create a new project and add a single class:

import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;

@RunWith(ClasspathSuite.class)
public class RunAllTests {
}

If you’re with Maven, the library can be referenced like this (if not follow this link):

 <repositories>
    <repository>
      <id>http://maven.xwiki.org</id>
      <url>http://maven.xwiki.org/externals</url>
    </repository>
  </repositories>
  
  <dependencies>
    <dependency>
      <groupId>cpsuite</groupId>
      <artifactId>cpsuite</artifactId>
      <version>1.2.5</version>
      <scope>test</scope>
    </dependency>
  </dependencies>


Now, make sure that the new project “sees” all test classes, i.e. add them to the classpath. Adding a maven dependency to the other projects didn’t work for me (using m2Eclipse). Probably, because tests classes are handled differently and are not compiled into the resulting jar. Anyway, adding a plain project dependency to the build path works fine and is ok, as we only want to use this project from within the IDE.

Now, simply call “Run as JUnit test” on this class or the entire project and watch others doing the work for you.

ClassPathSuite with GWT

When running all JUnit tests for a GWT front-end, some tests failed because of NoClassDefFoundErrors for some classes under test. It turned out, that all these classes had a static initializer with a GWT#create() call, e.g.

private static final SomeMessages MESSAGES = GWT.create( SomeMessages.class );

The GWT#create() call throws a UnsupportedOperationException when run in a non-browser environment and as this happens during the class’ initialization, the class cannot be loaded. Unfortunately, CPSuite’s class finder swallows all exceptions of this kind, so problems like this can be hard to track. Anyway, this problem can be solved with GWT’s helper class com.google.gwt.junit.GWTMockUtilities.

As classpath scanning happens during the creation of the ClassPathSuite instance, we have to invoke GWTMockUtilities#disarm() before the instance is created. One way is to inherit from the base class and use a static initializer:

import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;

import com.heiler.hsp.ui.testhelper.MockitoGWTMockUtilities;

public class GwtClassPathSuite extends ClasspathSuite {
  static {
    MockitoGWTMockUtilities.disarm(); // let all GWT#create() calls return null
  }

  public GwtClassPathSuite( Class<?> suiteClass, RunnerBuilder builder ) throws InitializationError {
    super( suiteClass, builder );
  }
}

The class to trigger all tests now references the inherited class:

import org.junit.runner.RunWith;

@RunWith(GwtClassPathSuite.class)
public class RunAllTests {
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: