bb.util
Class JUnitExecutor

java.lang.Object
  extended by bb.util.JUnitExecutor

public class JUnitExecutor
extends Object

Discovers and autoexecutes all the JUnit 4 test methods (i.e. those annotated Test) found in the class files of some directory tree. Offers filtering to fine tune which packages, classes, and methods in that directory tree are actually run.

Note: you should use at least JUnit 4.5 with this class, as there were bugs in earlier versions that were finally fixed in 4.5 (Early incarnations of this class coded around these bugs with hack code, but that hack code has now been removed, which leaves you vulnerable if you use older JUnit versions.)

While executing test methods, a JUnitExecutor.PrintStreamFeedback instance and a JUnitExecutor.AudioFeedback are used to provide feedback.

This class is multithread safe: it is immutable (both its immediate state, as well as the deep state of its fields).

Author:
Brent Boyer

Nested Class Summary
private static class JUnitExecutor.AudioFeedback
          Provides audio feedback for test events.
private static class JUnitExecutor.BufferWithEcho
          Modifies superclass to echo the last line stored in the buffer to the console after byte(s) are written to it.
private static class JUnitExecutor.DescriptionFields
          Parses and stores fields from a Description.
private static class JUnitExecutor.FindTestEvents
          Stores all events that occur while finding classes with JUnit tests, from which it can generate a report.
private static class JUnitExecutor.PcmFilter
          Filters on the basis of package, class, and method names (pcm).
private static class JUnitExecutor.PrintStreamFeedback
          Provides console feedback for test events.
private static class JUnitExecutor.RunListenerAbstract
          Defines some common functionality used by a couple of (otherwise very different) RunListener implementations.
private static class JUnitExecutor.StdStreams
          Swaps and unswaps the standard streams (System.out and System.err) for a pair of JUnitExecutor.BufferWithEcho instances.
private static class JUnitExecutor.StdStreamSwapper
          Every time that a test method is about to be executed, this intercepts the standard streams (out and err) and captures any output.
private static class JUnitExecutor.TestRunEvents
          Stores all events which occur during a test run, from which it can generate a report.
 
Field Summary
private static String classes_key
           
private  JUnitExecutor.FindTestEvents findTestEvents
           
private static List<String> keysLegal
          Specifies all the switch keys which can legally appear as command line arguments to main.
private static String methods_key
           
private static String packages_key
           
private static String root_key
           
private static File testOutputDirectory
           
private  JUnitExecutor.TestRunEvents testRunEvents
           
 
Constructor Summary
JUnitExecutor()
          Constructor.
 
Method Summary
private  boolean containsJUnitTests(Class c, JUnitExecutor.PcmFilter pcmFilter)
           
private  String extractClassName(File classFile)
           
private  String extractPackageName(File classFile, String pathRoot)
          Note: returns an empty String if classFile is in the default (unnamed) package.
private  Class[] findClassesWithJUnitTests(String root, JUnitExecutor.PcmFilter pcmFilter)
           
private  String getPath(File file)
          Returns a standard form for file's path: the separator is always '/' and directories end with a '/'.
private  Class loadClass(File classFile, String pathRoot)
           
static void main(String[] args)
          Creates a new JUnitExecutor instance and calls its run method.
private  boolean needsJUnitTests(Class c)
           
private static Set<Pattern> parseList(String key, Properties2 switches)
           
 void run(String root, JUnitExecutor.PcmFilter pcmFilter)
          Determines all the classes underneath root which contain JUnit 4 test methods (i.e. those which are annotated @Test) that pass pcmFilter.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

root_key

private static final String root_key
See Also:
Constant Field Values

packages_key

private static final String packages_key
See Also:
Constant Field Values

classes_key

private static final String classes_key
See Also:
Constant Field Values

methods_key

private static final String methods_key
See Also:
Constant Field Values

keysLegal

private static final List<String> keysLegal
Specifies all the switch keys which can legally appear as command line arguments to main.


testOutputDirectory

private static final File testOutputDirectory

findTestEvents

private final JUnitExecutor.FindTestEvents findTestEvents

testRunEvents

private final JUnitExecutor.TestRunEvents testRunEvents
Constructor Detail

JUnitExecutor

public JUnitExecutor()
Constructor.

Method Detail

main

public static void main(String[] args)
                 throws Exception
Creates a new JUnitExecutor instance and calls its run method.

The root param in that call to run is specified as a key/value pair in args of the form -root pathToRootDirectory.

The pcmFilter param in that call to run is specified using any combination of these filters:

  1. a key/value pair in args of the form -packages listOfPackageNames, for example -packages bb.io,bb.util or -packages bb.*, to restrict the running of test methods to only classes whose packages are in the list
  2. a key/value pair in args of the form -classes listOfSimpleClassNames, for example -classes Benchmark,Bootstrap or -classes ArrayUtil\$UnitTest,Benchmark\$UnitTest or -classes B.*, to restrict the running of test methods to only classes whose simple names (no package part) are in the list
  3. a key/value pair in args of the form -methods listOfMethodNames, for example -classes test_concatenate,test_shuffle or -classes te.*, to restrict the running of test methods to only those whose names are in the list
A given test method is only run if it passes every filter (i.e. there is an implied AND of all the filters).

For each filter, the value must be a single comma separated list with no spaces in the list. The list is parsed into elements, each of which is interpreted as a java regular expression. So, wildcards can be used as in the examples above. A given test method is run if it matches at least one element in the list (i.e. there is an implied OR of all the list elements).

If this method is this Java process's entry point (i.e. first main method), then its final action is a call to System.exit, which means that this method never returns; its exit code is 0 if it executes normally, 1 if it throws a Throwable (which will be caught and logged). Otherwise, this method returns and leaves the JVM running.

Throws:
Exception

parseList

private static Set<Pattern> parseList(String key,
                                      Properties2 switches)
                               throws Exception
Throws:
Exception

run

public void run(String root,
                JUnitExecutor.PcmFilter pcmFilter)
         throws Exception
Determines all the classes underneath root which contain JUnit 4 test methods (i.e. those which are annotated @Test) that pass pcmFilter. Then runs those tests using JUnit 4.

Note that root must be the sole directory which is the package root; it cannot be just any directory which contains the classes. For example, suppose that the directory D:/software/java/projectsMine/bbLibrary/class is the package root which contains class files like A.class and B.class (these would be in the default, unnamed package) as well as subdirectories that contain more class files (these would be in named packages). Then, root must have the value D:/software/java/projectsMine/bbLibrary/class. You would not use higher level directories like D:/software/java/projectsMine/bbLibrary or D:/software/java/projectsMine in this case because they are not the package root.

Throws:
Exception - of some kind if any is raised

findClassesWithJUnitTests

private Class[] findClassesWithJUnitTests(String root,
                                          JUnitExecutor.PcmFilter pcmFilter)
                                   throws Exception
Throws:
Exception

getPath

private String getPath(File file)
Returns a standard form for file's path: the separator is always '/' and directories end with a '/'.


extractPackageName

private String extractPackageName(File classFile,
                                  String pathRoot)
                           throws IllegalStateException
Note: returns an empty String if classFile is in the default (unnamed) package.

Throws:
IllegalStateException

extractClassName

private String extractClassName(File classFile)

loadClass

private Class loadClass(File classFile,
                        String pathRoot)
                 throws Exception
Throws:
Exception

containsJUnitTests

private boolean containsJUnitTests(Class c,
                                   JUnitExecutor.PcmFilter pcmFilter)

needsJUnitTests

private boolean needsJUnitTests(Class c)