Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I programmatically run all the JUnit tests in my Java application?

From Eclipse I can easily run all the JUnit tests in my application.

I would like to be able to run the tests on target systems from the application jar, without Eclipse (or Ant or Maven or any other development tool).

I can see how to run a specific test or suite from the command line.

I could manually create a suite listing all the tests in my application, but that seems error prone - I'm sure at some point I'll create a test and forget to add it to the suite.

The Eclipse JUnit plugin has a wizard to create a test suite, but for some reason it doesn't "see" my test classes. It may be looking for JUnit 3 tests, not JUnit 4 annotated tests.

I could write a tool that would automatically create the suite by scanning the source files.

Or I could write code so the application would scan it's own jar file for tests (either by naming convention or by looking for the @Test annotation).

It seems like there should be an easier way. What am I missing?

like image 583
Andrew McKinlay Avatar asked Mar 09 '10 19:03

Andrew McKinlay


2 Answers

According to a recent thread on the JUnit mailing list, ClasspathSuite can collect and run all JUnit tests on the classpath. It is not precisely what you want, since it is a class-level annotation, but the source is available, so you may be able to extend its internal discovery mechanism.

like image 145
Brett Daniel Avatar answered Oct 22 '22 19:10

Brett Daniel


Based on http://burtbeckwith.com/blog/?p=52 I came up with the following. It seems to work well.

I can run it from within my code with:

org.junit.runner.JUnitCore.main("suneido.AllTestsSuite");

One weak point is that it relies on a naming convention ("Test" suffix) to identify tests. Another weak point is that the name of the jar file is hard coded.

package suneido;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;

/**
 * Discovers all JUnit tests in a jar file and runs them in a suite.
 */
@RunWith(AllTestsSuite.AllTestsRunner.class)
public final class AllTestsSuite {
    private final static String JARFILE = "jsuneido.jar";

    private AllTestsSuite() {
    }

    public static class AllTestsRunner extends Suite {

        public AllTestsRunner(final Class<?> clazz) throws InitializationError {
            super(clazz, findClasses());
        }

        private static Class<?>[] findClasses() {
            List<String> classFiles = new ArrayList<String>();
            findClasses(classFiles);
            List<Class<?>> classes = convertToClasses(classFiles);
            return classes.toArray(new Class[classes.size()]);
        }

        private static void findClasses(final List<String> classFiles) {
            JarFile jf;
            try {
                jf = new JarFile(JARFILE);
                for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {
                    String name = e.nextElement().getName();
                    if (name.startsWith("suneido/") && name.endsWith("Test.class")
                            && !name.contains("$"))
                        classFiles.add(name.replaceAll("/", ".")
                                .substring(0, name.length() - 6));
                }
                jf.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        private static List<Class<?>> convertToClasses(
                final List<String> classFiles) {
            List<Class<?>> classes = new ArrayList<Class<?>>();
            for (String name : classFiles) {
                Class<?> c;
                try {
                    c = Class.forName(name);
                }
                catch (ClassNotFoundException e) {
                    throw new AssertionError(e);
                }
                if (!Modifier.isAbstract(c.getModifiers())) {
                    classes.add(c);
                }
            }
            return classes;
        }
    }

}
like image 5
Andrew McKinlay Avatar answered Oct 22 '22 20:10

Andrew McKinlay