Home | History | Annotate | Download | only in runners
      1 package org.junit.runners;
      2 
      3 import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
      4 
      5 import java.lang.annotation.Annotation;
      6 import java.lang.reflect.Method;
      7 import java.util.ArrayList;
      8 import java.util.Collections;
      9 import java.util.Comparator;
     10 import java.util.Iterator;
     11 import java.util.List;
     12 
     13 import org.junit.AfterClass;
     14 import org.junit.BeforeClass;
     15 import org.junit.ClassRule;
     16 import org.junit.Rule;
     17 import org.junit.internal.AssumptionViolatedException;
     18 import org.junit.internal.runners.model.EachTestNotifier;
     19 import org.junit.internal.runners.statements.RunAfters;
     20 import org.junit.internal.runners.statements.RunBefores;
     21 import org.junit.rules.RunRules;
     22 import org.junit.rules.TestRule;
     23 import org.junit.runner.Description;
     24 import org.junit.runner.Runner;
     25 import org.junit.runner.manipulation.Filter;
     26 import org.junit.runner.manipulation.Filterable;
     27 import org.junit.runner.manipulation.NoTestsRemainException;
     28 import org.junit.runner.manipulation.Sortable;
     29 import org.junit.runner.manipulation.Sorter;
     30 import org.junit.runner.notification.RunNotifier;
     31 import org.junit.runner.notification.StoppedByUserException;
     32 import org.junit.runners.model.FrameworkMethod;
     33 import org.junit.runners.model.InitializationError;
     34 import org.junit.runners.model.MultipleFailureException;
     35 import org.junit.runners.model.RunnerScheduler;
     36 import org.junit.runners.model.Statement;
     37 import org.junit.runners.model.TestClass;
     38 
     39 /**
     40  * Provides most of the functionality specific to a Runner that implements a
     41  * "parent node" in the test tree, with children defined by objects of some data
     42  * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
     43  * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
     44  * must implement finding the children of the node, describing each child, and
     45  * running each child. ParentRunner will filter and sort children, handle
     46  * {@code @BeforeClass} and {@code @AfterClass} methods,
     47  * handle annotated {@link ClassRule}s, create a composite
     48  * {@link Description}, and run children sequentially.
     49  */
     50 public abstract class ParentRunner<T> extends Runner implements Filterable,
     51 		Sortable {
     52 	private final TestClass fTestClass;
     53 
     54 	private Sorter fSorter= Sorter.NULL;
     55 
     56 	private List<T> fFilteredChildren= null;
     57 
     58 	private RunnerScheduler fScheduler= new RunnerScheduler() {
     59 		public void schedule(Runnable childStatement) {
     60 			childStatement.run();
     61 		}
     62 
     63 		public void finished() {
     64 			// do nothing
     65 		}
     66 	};
     67 
     68 	/**
     69 	 * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
     70 	 * @throws InitializationError
     71 	 */
     72 	protected ParentRunner(Class<?> testClass) throws InitializationError {
     73 		fTestClass= new TestClass(testClass);
     74 		validate();
     75 	}
     76 
     77 	//
     78 	// Must be overridden
     79 	//
     80 
     81 	/**
     82 	 * Returns a list of objects that define the children of this Runner.
     83 	 */
     84 	protected abstract List<T> getChildren();
     85 
     86 	/**
     87 	 * Returns a {@link Description} for {@code child}, which can be assumed to
     88 	 * be an element of the list returned by {@link ParentRunner#getChildren()}
     89 	 */
     90 	protected abstract Description describeChild(T child);
     91 
     92 	/**
     93 	 * Runs the test corresponding to {@code child}, which can be assumed to be
     94 	 * an element of the list returned by {@link ParentRunner#getChildren()}.
     95 	 * Subclasses are responsible for making sure that relevant test events are
     96 	 * reported through {@code notifier}
     97 	 */
     98 	protected abstract void runChild(T child, RunNotifier notifier);
     99 
    100 	//
    101 	// May be overridden
    102 	//
    103 
    104 	/**
    105 	 * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
    106 	 * Default implementation adds an error for each method annotated with
    107 	 * {@code @BeforeClass} or {@code @AfterClass} that is not
    108 	 * {@code public static void} with no arguments.
    109 	 */
    110 	protected void collectInitializationErrors(List<Throwable> errors) {
    111 		validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
    112 		validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
    113 		validateClassRules(errors);
    114 	}
    115 
    116 	/**
    117 	 * Adds to {@code errors} if any method in this class is annotated with
    118 	 * {@code annotation}, but:
    119 	 * <ul>
    120 	 * <li>is not public, or
    121 	 * <li>takes parameters, or
    122 	 * <li>returns something other than void, or
    123 	 * <li>is static (given {@code isStatic is false}), or
    124 	 * <li>is not static (given {@code isStatic is true}).
    125 	 */
    126 	protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
    127 			boolean isStatic, List<Throwable> errors) {
    128 		List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(annotation);
    129 
    130 		for (FrameworkMethod eachTestMethod : methods)
    131 			eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
    132 	}
    133 
    134 	private void validateClassRules(List<Throwable> errors) {
    135 		CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
    136 	}
    137 
    138 	/**
    139 	 * Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing.
    140 	 * Here is an outline of the implementation:
    141 	 * <ul>
    142 	 * <li>Call {@link #runChild(Object, RunNotifier)} on each object returned by {@link #getChildren()} (subject to any imposed filter and sort).</li>
    143 	 * <li>ALWAYS run all non-overridden {@code @BeforeClass} methods on this class
    144 	 * and superclasses before the previous step; if any throws an
    145 	 * Exception, stop execution and pass the exception on.
    146 	 * <li>ALWAYS run all non-overridden {@code @AfterClass} methods on this class
    147 	 * and superclasses before any of the previous steps; all AfterClass methods are
    148 	 * always executed: exceptions thrown by previous steps are combined, if
    149 	 * necessary, with exceptions from AfterClass methods into a
    150 	 * {@link MultipleFailureException}.
    151 	 * </ul>
    152 	 * @param notifier
    153 	 * @return {@code Statement}
    154 	 */
    155 	protected Statement classBlock(final RunNotifier notifier) {
    156 		Statement statement= childrenInvoker(notifier);
    157 		statement= withBeforeClasses(statement);
    158 		statement= withAfterClasses(statement);
    159 		statement= withClassRules(statement);
    160 		return statement;
    161 	}
    162 
    163 	/**
    164 	 * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
    165 	 * and superclasses before executing {@code statement}; if any throws an
    166 	 * Exception, stop execution and pass the exception on.
    167 	 */
    168 	protected Statement withBeforeClasses(Statement statement) {
    169 		List<FrameworkMethod> befores= fTestClass
    170 				.getAnnotatedMethods(BeforeClass.class);
    171 		return befores.isEmpty() ? statement :
    172 			new RunBefores(statement, befores, null);
    173 	}
    174 
    175 	/**
    176 	 * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
    177 	 * and superclasses before executing {@code statement}; all AfterClass methods are
    178 	 * always executed: exceptions thrown by previous steps are combined, if
    179 	 * necessary, with exceptions from AfterClass methods into a
    180 	 * {@link MultipleFailureException}.
    181 	 */
    182 	protected Statement withAfterClasses(Statement statement) {
    183 		List<FrameworkMethod> afters= fTestClass
    184 				.getAnnotatedMethods(AfterClass.class);
    185 		return afters.isEmpty() ? statement :
    186 			new RunAfters(statement, afters, null);
    187 	}
    188 
    189 	/**
    190 	 * Returns a {@link Statement}: apply all
    191 	 * static fields assignable to {@link TestRule}
    192 	 * annotated with {@link ClassRule}.
    193 	 *
    194 	 * @param statement
    195 	 *            the base statement
    196 	 * @return a RunRules statement if any class-level {@link Rule}s are
    197 	 *         found, or the base statement
    198 	 */
    199 	private Statement withClassRules(Statement statement) {
    200 		List<TestRule> classRules= classRules();
    201 		return classRules.isEmpty() ? statement :
    202 		    new RunRules(statement, classRules, getDescription());
    203 	}
    204 
    205 	/**
    206 	 * @return the {@code ClassRule}s that can transform the block that runs
    207 	 *         each method in the tested class.
    208 	 */
    209 	protected List<TestRule> classRules() {
    210 		return fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class);
    211 	}
    212 
    213 	/**
    214 	 * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
    215 	 * on each object returned by {@link #getChildren()} (subject to any imposed
    216 	 * filter and sort)
    217 	 */
    218 	protected Statement childrenInvoker(final RunNotifier notifier) {
    219 		return new Statement() {
    220 			@Override
    221 			public void evaluate() {
    222 				runChildren(notifier);
    223 			}
    224 		};
    225 	}
    226 
    227 	private void runChildren(final RunNotifier notifier) {
    228 		for (final T each : getFilteredChildren())
    229  			fScheduler.schedule(new Runnable() {
    230 				public void run() {
    231 					ParentRunner.this.runChild(each, notifier);
    232 				}
    233 			});
    234 		fScheduler.finished();
    235 	}
    236 
    237 	/**
    238 	 * Returns a name used to describe this Runner
    239 	 */
    240 	protected String getName() {
    241 		return fTestClass.getName();
    242 	}
    243 
    244 	//
    245 	// Available for subclasses
    246 	//
    247 
    248 	/**
    249 	 * Returns a {@link TestClass} object wrapping the class to be executed.
    250 	 */
    251 	public final TestClass getTestClass() {
    252 		return fTestClass;
    253 	}
    254 
    255 	/**
    256 	 * Runs a {@link Statement} that represents a leaf (aka atomic) test.
    257 	 */
    258 	protected final void runLeaf(Statement statement, Description description,
    259 			RunNotifier notifier) {
    260 		EachTestNotifier eachNotifier= new EachTestNotifier(notifier, description);
    261 		eachNotifier.fireTestStarted();
    262 		try {
    263 		    statement.evaluate();
    264 		} catch (AssumptionViolatedException e) {
    265 			eachNotifier.addFailedAssumption(e);
    266 		} catch (Throwable e) {
    267 			eachNotifier.addFailure(e);
    268 		} finally {
    269 			eachNotifier.fireTestFinished();
    270 		}
    271 	}
    272 
    273 	/**
    274 	 * @return the annotations that should be attached to this runner's
    275 	 * description.
    276 	 */
    277 	protected Annotation[] getRunnerAnnotations() {
    278 		return fTestClass.getAnnotations();
    279 	}
    280 
    281 	//
    282 	// Implementation of Runner
    283 	//
    284 
    285 	@Override
    286 	public Description getDescription() {
    287 		Description description= Description.createSuiteDescription(getName(),
    288 				getRunnerAnnotations());
    289 		for (T child : getFilteredChildren())
    290 			description.addChild(describeChild(child));
    291 		return description;
    292 	}
    293 
    294 	@Override
    295 	public void run(final RunNotifier notifier) {
    296 		EachTestNotifier testNotifier= new EachTestNotifier(notifier,
    297 				getDescription());
    298 		try {
    299 			Statement statement= classBlock(notifier);
    300 			statement.evaluate();
    301 		} catch (AssumptionViolatedException e) {
    302 			testNotifier.fireTestIgnored();
    303 		} catch (StoppedByUserException e) {
    304 			throw e;
    305 		} catch (Throwable e) {
    306 			testNotifier.addFailure(e);
    307 		}
    308 	}
    309 
    310 	//
    311 	// Implementation of Filterable and Sortable
    312 	//
    313 
    314 	public void filter(Filter filter) throws NoTestsRemainException {
    315 		for (Iterator<T> iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
    316 			T each = iter.next();
    317 			if (shouldRun(filter, each))
    318 				try {
    319 					filter.apply(each);
    320 				} catch (NoTestsRemainException e) {
    321 					iter.remove();
    322 				}
    323 			else
    324 				iter.remove();
    325 		}
    326 	    if (getFilteredChildren().isEmpty()) {
    327 	        throw new NoTestsRemainException();
    328 	    }
    329 	}
    330 
    331 	public void sort(Sorter sorter) {
    332 		fSorter= sorter;
    333 		for (T each : getFilteredChildren())
    334 			sortChild(each);
    335 		Collections.sort(getFilteredChildren(), comparator());
    336 	}
    337 
    338 	//
    339 	// Private implementation
    340 	//
    341 
    342 	private void validate() throws InitializationError {
    343 		List<Throwable> errors= new ArrayList<Throwable>();
    344 		collectInitializationErrors(errors);
    345 		if (!errors.isEmpty())
    346 			throw new InitializationError(errors);
    347 	}
    348 
    349 	private List<T> getFilteredChildren() {
    350 		if (fFilteredChildren == null)
    351 			fFilteredChildren = new ArrayList<T>(getChildren());
    352 		return fFilteredChildren;
    353 	}
    354 
    355 	private void sortChild(T child) {
    356 		fSorter.apply(child);
    357 	}
    358 
    359 	private boolean shouldRun(Filter filter, T each) {
    360 		return filter.shouldRun(describeChild(each));
    361 	}
    362 
    363 	private Comparator<? super T> comparator() {
    364 		return new Comparator<T>() {
    365 			public int compare(T o1, T o2) {
    366 				return fSorter.compare(describeChild(o1), describeChild(o2));
    367 			}
    368 		};
    369 	}
    370 
    371 	/**
    372 	 * Sets a scheduler that determines the order and parallelization
    373 	 * of children.  Highly experimental feature that may change.
    374 	 */
    375 	public void setScheduler(RunnerScheduler scheduler) {
    376 		this.fScheduler = scheduler;
    377 	}
    378 }
    379