Search code examples
eclipsejunit4

How can I recursively find and run all Junit 4 tests within Eclipse?


I would like to run all junit 4 tests within my Eclipse project. The project is setup with /source and /test. Under /test are various packages, such as:

com.yaddayadda.test.core.entity
com.yaddayadda.test.core.framework

If I right-click at the /test level in Package Explorer and choose Run As; Junit Test I receive the error:

No tests found with test runner 'JUnit 4'.

If I right-click on com.yaddayadda.test.core.entity, then it finds and runs all the tests within that package. So the @Test annotations are correct (they are also picked up by Ant correctly on the build server). However, if I try and run all tests within com.yaddayadda.test.core then it finds none.

Basically, it only seems to look within the package rather the recusively at all children. Is there a way to fix this?


Solution

  • Incase anyone else is looking for a solution to this, I found an answer here on Burt Beckwith's website:

    http://burtbeckwith.com/blog/?p=52

    To use this, just right-click it in the class tree in Eclipse and click “Run As JUnit Test”.

    import java.io.File;
    import java.io.UnsupportedEncodingException;
    import java.lang.reflect.Modifier;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import org.apache.log4j.Logger;
    import org.junit.internal.runners.InitializationError;
    import org.junit.runner.Description;
    import org.junit.runner.RunWith;
    import org.junit.runner.notification.RunListener;
    import org.junit.runner.notification.RunNotifier;
    import org.junit.runners.Suite;
    
    /**
     * Discovers all JUnit tests and runs them in a suite.
     */
    @RunWith(AllTests.AllTestsRunner.class)
    public final class AllTests {
    
      private static final File CLASSES_DIR = findClassesDir();
    
      private AllTests() {
        // static only
      }
    
      /**
       * Finds and runs tests.
       */
      public static class AllTestsRunner extends Suite {
    
        private final Logger _log = Logger.getLogger(getClass());
    
        /**
         * Constructor.
         *
         * @param clazz  the suite class - <code>AllTests</code>
         * @throws InitializationError  if there's a problem
         */
        public AllTestsRunner(final Class<?> clazz) throws InitializationError {
          super(clazz, findClasses());
        }
    
        /**
         * {@inheritDoc}
         * @see org.junit.runners.Suite#run(org.junit.runner.notification.RunNotifier)
         */
        @Override
        public void run(final RunNotifier notifier) {
          initializeBeforeTests();
    
          notifier.addListener(new RunListener() {
            @Override
            public void testStarted(final Description description) {
              if (_log.isTraceEnabled()) {
                _log.trace("Before test " + description.getDisplayName());
              }
            }
    
            @Override
            public void testFinished(final Description description) {
              if (_log.isTraceEnabled()) {
                _log.trace("After test " + description.getDisplayName());
              }
            }
          });
    
          super.run(notifier);
        }
    
        private static Class<?>[] findClasses() {
          List<File> classFiles = new ArrayList<File>();
          findClasses(classFiles, CLASSES_DIR);
          List<Class<?>> classes = convertToClasses(classFiles, CLASSES_DIR);
          return classes.toArray(new Class[classes.size()]);
        }
    
        private static void initializeBeforeTests() {
          // do one-time initialization here
        }
    
        private static List<Class<?>> convertToClasses(
            final List<File> classFiles, final File classesDir) {
    
          List<Class<?>> classes = new ArrayList<Class<?>>();
          for (File file : classFiles) {
            if (!file.getName().endsWith("Test.class")) {
              continue;
            }
            String name = file.getPath().substring(classesDir.getPath().length() + 1)
              .replace('/', '.')
              .replace('\\', '.');
            name = name.substring(0, name.length() - 6);
            Class<?> c;
            try {
              c = Class.forName(name);
            }
            catch (ClassNotFoundException e) {
              throw new AssertionError(e);
            }
            if (!Modifier.isAbstract(c.getModifiers())) {
              classes.add(c);
            }
          }
    
          // sort so we have the same order as Ant
          Collections.sort(classes, new Comparator<Class<?>>() {
            public int compare(final Class<?> c1, final Class<?> c2) {
              return c1.getName().compareTo(c2.getName());
            }
          });
    
          return classes;
        }
    
        private static void findClasses(final List<File> classFiles, final File dir) {
          for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
              findClasses(classFiles, file);
            }
            else if (file.getName().toLowerCase().endsWith(".class")) {
              classFiles.add(file);
            }
          }
        }
      }
    
      private static File findClassesDir() {
        try {
          String path = AllTests.class.getProtectionDomain()
            .getCodeSource().getLocation().getFile();
          return new File(URLDecoder.decode(path, "UTF-8"));
        }
        catch (UnsupportedEncodingException impossible) {
          // using default encoding, has to exist
          throw new AssertionError(impossible);
        }
      }
    }