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