1 package org.junit.runners;
2 
3 import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR;
4 import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR;
5 
6 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.concurrent.ConcurrentHashMap;
9 import java.util.concurrent.ConcurrentMap;
10 import java.util.concurrent.TimeUnit;
11 
12 import org.junit.After;
13 import org.junit.Before;
14 import org.junit.Ignore;
15 import org.junit.Rule;
16 import org.junit.Test;
17 import org.junit.Test.None;
18 import org.junit.internal.runners.model.ReflectiveCallable;
19 import org.junit.internal.runners.statements.ExpectException;
20 import org.junit.internal.runners.statements.Fail;
21 import org.junit.internal.runners.statements.FailOnTimeout;
22 import org.junit.internal.runners.statements.InvokeMethod;
23 import org.junit.internal.runners.statements.RunAfters;
24 import org.junit.internal.runners.statements.RunBefores;
25 import org.junit.rules.MethodRule;
26 import org.junit.rules.TestRule;
27 import org.junit.runner.Description;
28 import org.junit.runner.notification.RunNotifier;
29 import org.junit.runners.model.FrameworkMember;
30 import org.junit.runners.model.FrameworkMethod;
31 import org.junit.runners.model.InitializationError;
32 import org.junit.runners.model.MemberValueConsumer;
33 import org.junit.runners.model.MultipleFailureException;
34 import org.junit.runners.model.Statement;
35 import org.junit.runners.model.TestClass;
36 import org.junit.validator.PublicClassValidator;
37 import org.junit.validator.TestClassValidator;
38 
39 /**
40  * Implements the JUnit 4 standard test case class model, as defined by the
41  * annotations in the org.junit package. Many users will never notice this
42  * class: it is now the default test class runner, but it should have exactly
43  * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
44  * <p>
45  * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
46  * that are slight changes to the default behavior, however:
47  *
48  * <ul>
49  * <li>It has a much simpler implementation based on {@link Statement}s,
50  * allowing new operations to be inserted into the appropriate point in the
51  * execution flow.
52  *
53  * <li>It is published, and extension and reuse are encouraged, whereas {@code
54  * JUnit4ClassRunner} was in an internal package, and is now deprecated.
55  * </ul>
56  * <p>
57  * In turn, in 2009 we introduced {@link Rule}s.  In many cases where extending
58  * BlockJUnit4ClassRunner was necessary to add new behavior, {@link Rule}s can
59  * be used, which makes the extension more reusable and composable.
60  *
61  * @since 4.5
62  */
63 public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
64     private static TestClassValidator PUBLIC_CLASS_VALIDATOR = new PublicClassValidator();
65 
66     private final ConcurrentMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>();
67 
68     /**
69      * Creates a BlockJUnit4ClassRunner to run {@code testClass}
70      *
71      * @throws InitializationError if the test class is malformed.
72      */
BlockJUnit4ClassRunner(Class<?> testClass)73     public BlockJUnit4ClassRunner(Class<?> testClass) throws InitializationError {
74         super(testClass);
75     }
76 
77     /**
78      * Creates a BlockJUnit4ClassRunner to run {@code testClass}.
79      *
80      * @throws InitializationError if the test class is malformed.
81      * @since 4.13
82      */
BlockJUnit4ClassRunner(TestClass testClass)83     protected BlockJUnit4ClassRunner(TestClass testClass) throws InitializationError {
84         super(testClass);
85     }
86 
87     //
88     // Implementation of ParentRunner
89     //
90 
91     @Override
runChild(final FrameworkMethod method, RunNotifier notifier)92     protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
93         Description description = describeChild(method);
94         if (isIgnored(method)) {
95             notifier.fireTestIgnored(description);
96         } else {
97             Statement statement = new Statement() {
98                 @Override
99                 public void evaluate() throws Throwable {
100                     methodBlock(method).evaluate();
101                 }
102             };
103             runLeaf(statement, description, notifier);
104         }
105     }
106 
107     /**
108      * Evaluates whether {@link FrameworkMethod}s are ignored based on the
109      * {@link Ignore} annotation.
110      */
111     @Override
isIgnored(FrameworkMethod child)112     protected boolean isIgnored(FrameworkMethod child) {
113         return child.getAnnotation(Ignore.class) != null;
114     }
115 
116     @Override
describeChild(FrameworkMethod method)117     protected Description describeChild(FrameworkMethod method) {
118         Description description = methodDescriptions.get(method);
119 
120         if (description == null) {
121             description = Description.createTestDescription(getTestClass().getJavaClass(),
122                     testName(method), method.getAnnotations());
123             methodDescriptions.putIfAbsent(method, description);
124         }
125 
126         return description;
127     }
128 
129     @Override
getChildren()130     protected List<FrameworkMethod> getChildren() {
131         return computeTestMethods();
132     }
133 
134     //
135     // Override in subclasses
136     //
137 
138     /**
139      * Returns the methods that run tests. Default implementation returns all
140      * methods annotated with {@code @Test} on this class and superclasses that
141      * are not overridden.
142      */
computeTestMethods()143     protected List<FrameworkMethod> computeTestMethods() {
144         return getTestClass().getAnnotatedMethods(Test.class);
145     }
146 
147     @Override
collectInitializationErrors(List<Throwable> errors)148     protected void collectInitializationErrors(List<Throwable> errors) {
149         super.collectInitializationErrors(errors);
150 
151         validatePublicConstructor(errors);
152         validateNoNonStaticInnerClass(errors);
153         validateConstructor(errors);
154         validateInstanceMethods(errors);
155         validateFields(errors);
156         validateMethods(errors);
157     }
158 
validatePublicConstructor(List<Throwable> errors)159     private void validatePublicConstructor(List<Throwable> errors) {
160         if (getTestClass().getJavaClass() != null) {
161             errors.addAll(PUBLIC_CLASS_VALIDATOR.validateTestClass(getTestClass()));
162         }
163     }
164 
validateNoNonStaticInnerClass(List<Throwable> errors)165     protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
166         if (getTestClass().isANonStaticInnerClass()) {
167             String gripe = "The inner class " + getTestClass().getName()
168                     + " is not static.";
169             errors.add(new Exception(gripe));
170         }
171     }
172 
173     /**
174      * Adds to {@code errors} if the test class has more than one constructor,
175      * or if the constructor takes parameters. Override if a subclass requires
176      * different validation rules.
177      */
validateConstructor(List<Throwable> errors)178     protected void validateConstructor(List<Throwable> errors) {
179         validateOnlyOneConstructor(errors);
180         validateZeroArgConstructor(errors);
181     }
182 
183     /**
184      * Adds to {@code errors} if the test class has more than one constructor
185      * (do not override)
186      */
validateOnlyOneConstructor(List<Throwable> errors)187     protected void validateOnlyOneConstructor(List<Throwable> errors) {
188         if (!hasOneConstructor()) {
189             String gripe = "Test class should have exactly one public constructor";
190             errors.add(new Exception(gripe));
191         }
192     }
193 
194     /**
195      * Adds to {@code errors} if the test class's single constructor takes
196      * parameters (do not override)
197      */
validateZeroArgConstructor(List<Throwable> errors)198     protected void validateZeroArgConstructor(List<Throwable> errors) {
199         if (!getTestClass().isANonStaticInnerClass()
200                 && hasOneConstructor()
201                 && (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
202             String gripe = "Test class should have exactly one public zero-argument constructor";
203             errors.add(new Exception(gripe));
204         }
205     }
206 
hasOneConstructor()207     private boolean hasOneConstructor() {
208         return getTestClass().getJavaClass().getConstructors().length == 1;
209     }
210 
211     /**
212      * Adds to {@code errors} for each method annotated with {@code @Test},
213      * {@code @Before}, or {@code @After} that is not a public, void instance
214      * method with no arguments.
215      * @deprecated
216      */
217     @Deprecated
validateInstanceMethods(List<Throwable> errors)218     protected void validateInstanceMethods(List<Throwable> errors) {
219         validatePublicVoidNoArgMethods(After.class, false, errors);
220         validatePublicVoidNoArgMethods(Before.class, false, errors);
221         validateTestMethods(errors);
222 
223         if (computeTestMethods().isEmpty()) {
224             errors.add(new Exception("No runnable methods"));
225         }
226     }
227 
validateFields(List<Throwable> errors)228     protected void validateFields(List<Throwable> errors) {
229         RULE_VALIDATOR.validate(getTestClass(), errors);
230     }
231 
validateMethods(List<Throwable> errors)232     private void validateMethods(List<Throwable> errors) {
233         RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
234     }
235 
236     /**
237      * Adds to {@code errors} for each method annotated with {@code @Test}that
238      * is not a public, void instance method with no arguments.
239      */
validateTestMethods(List<Throwable> errors)240     protected void validateTestMethods(List<Throwable> errors) {
241         validatePublicVoidNoArgMethods(Test.class, false, errors);
242     }
243 
244     /**
245      * Returns a new fixture for running a test. Default implementation executes
246      * the test class's no-argument constructor (validation should have ensured
247      * one exists).
248      */
createTest()249     protected Object createTest() throws Exception {
250         return getTestClass().getOnlyConstructor().newInstance();
251     }
252 
253     /**
254      * Returns a new fixture to run a particular test {@code method} against.
255      * Default implementation executes the no-argument {@link #createTest()} method.
256      *
257      * @since 4.13
258      */
createTest(FrameworkMethod method)259     protected Object createTest(FrameworkMethod method) throws Exception {
260         return createTest();
261     }
262 
263     /**
264      * Returns the name that describes {@code method} for {@link Description}s.
265      * Default implementation is the method's name
266      */
testName(FrameworkMethod method)267     protected String testName(FrameworkMethod method) {
268         return method.getName();
269     }
270 
271     /**
272      * Returns a Statement that, when executed, either returns normally if
273      * {@code method} passes, or throws an exception if {@code method} fails.
274      *
275      * Here is an outline of the default implementation:
276      *
277      * <ul>
278      * <li>Invoke {@code method} on the result of {@link #createTest(org.junit.runners.model.FrameworkMethod)}, and
279      * throw any exceptions thrown by either operation.
280      * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@link Test#expected()}
281      * attribute, return normally only if the previous step threw an
282      * exception of the correct type, and throw an exception otherwise.
283      * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
284      * timeout} attribute, throw an exception if the previous step takes more
285      * than the specified number of milliseconds.
286      * <li>ALWAYS run all non-overridden {@code @Before} methods on this class
287      * and superclasses before any of the previous steps; if any throws an
288      * Exception, stop execution and pass the exception on.
289      * <li>ALWAYS run all non-overridden {@code @After} methods on this class
290      * and superclasses after any of the previous steps; all After methods are
291      * always executed: exceptions thrown by previous steps are combined, if
292      * necessary, with exceptions from After methods into a
293      * {@link MultipleFailureException}.
294      * <li>ALWAYS allow {@code @Rule} fields to modify the execution of the
295      * above steps. A {@code Rule} may prevent all execution of the above steps,
296      * or add additional behavior before and after, or modify thrown exceptions.
297      * For more information, see {@link TestRule}
298      * </ul>
299      *
300      * This can be overridden in subclasses, either by overriding this method,
301      * or the implementations creating each sub-statement.
302      */
methodBlock(final FrameworkMethod method)303     protected Statement methodBlock(final FrameworkMethod method) {
304         Object test;
305         try {
306             test = new ReflectiveCallable() {
307                 @Override
308                 protected Object runReflectiveCall() throws Throwable {
309                     return createTest(method);
310                 }
311             }.run();
312         } catch (Throwable e) {
313             return new Fail(e);
314         }
315 
316         Statement statement = methodInvoker(method, test);
317         statement = possiblyExpectingExceptions(method, test, statement);
318         statement = withPotentialTimeout(method, test, statement);
319         statement = withBefores(method, test, statement);
320         statement = withAfters(method, test, statement);
321         statement = withRules(method, test, statement);
322         statement = withInterruptIsolation(statement);
323         return statement;
324     }
325 
326     //
327     // Statement builders
328     //
329 
330     /**
331      * Returns a {@link Statement} that invokes {@code method} on {@code test}
332      */
methodInvoker(FrameworkMethod method, Object test)333     protected Statement methodInvoker(FrameworkMethod method, Object test) {
334         return new InvokeMethod(method, test);
335     }
336 
337     /**
338      * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
339      * has the {@link Test#expected()} attribute, return normally only if {@code next}
340      * throws an exception of the correct type, and throw an exception
341      * otherwise.
342      */
possiblyExpectingExceptions(FrameworkMethod method, Object test, Statement next)343     protected Statement possiblyExpectingExceptions(FrameworkMethod method,
344             Object test, Statement next) {
345         Test annotation = method.getAnnotation(Test.class);
346         Class<? extends Throwable> expectedExceptionClass = getExpectedException(annotation);
347         return expectedExceptionClass != null ? new ExpectException(next, expectedExceptionClass) : next;
348     }
349 
350     /**
351      * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
352      * has the {@code timeout} attribute, throw an exception if {@code next}
353      * takes more than the specified number of milliseconds.
354      * @deprecated
355      */
356     @Deprecated
withPotentialTimeout(FrameworkMethod method, Object test, Statement next)357     protected Statement withPotentialTimeout(FrameworkMethod method,
358             Object test, Statement next) {
359         long timeout = getTimeout(method.getAnnotation(Test.class));
360         if (timeout <= 0) {
361             return next;
362         }
363         return FailOnTimeout.builder()
364                .withTimeout(timeout, TimeUnit.MILLISECONDS)
365                .build(next);
366     }
367 
368     /**
369      * Returns a {@link Statement}: run all non-overridden {@code @Before}
370      * methods on this class and superclasses before running {@code next}; if
371      * any throws an Exception, stop execution and pass the exception on.
372      */
withBefores(FrameworkMethod method, Object target, Statement statement)373     protected Statement withBefores(FrameworkMethod method, Object target,
374             Statement statement) {
375         List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(
376                 Before.class);
377         return befores.isEmpty() ? statement : new RunBefores(statement,
378                 befores, target);
379     }
380 
381     /**
382      * Returns a {@link Statement}: run all non-overridden {@code @After}
383      * methods on this class and superclasses before running {@code next}; all
384      * After methods are always executed: exceptions thrown by previous steps
385      * are combined, if necessary, with exceptions from After methods into a
386      * {@link MultipleFailureException}.
387      */
withAfters(FrameworkMethod method, Object target, Statement statement)388     protected Statement withAfters(FrameworkMethod method, Object target,
389             Statement statement) {
390         List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(
391                 After.class);
392         return afters.isEmpty() ? statement : new RunAfters(statement, afters,
393                 target);
394     }
395 
withRules(FrameworkMethod method, Object target, Statement statement)396     private Statement withRules(FrameworkMethod method, Object target, Statement statement) {
397         RuleContainer ruleContainer = new RuleContainer();
398         CURRENT_RULE_CONTAINER.set(ruleContainer);
399         try {
400             List<TestRule> testRules = getTestRules(target);
401             for (MethodRule each : rules(target)) {
402                 if (!(each instanceof TestRule && testRules.contains(each))) {
403                     ruleContainer.add(each);
404                 }
405             }
406             for (TestRule rule : testRules) {
407                 ruleContainer.add(rule);
408             }
409         } finally {
410             CURRENT_RULE_CONTAINER.remove();
411         }
412         return ruleContainer.apply(method, describeChild(method), target, statement);
413     }
414 
415     /**
416      * @param target the test case instance
417      * @return a list of MethodRules that should be applied when executing this
418      *         test
419      */
rules(Object target)420     protected List<MethodRule> rules(Object target) {
421         RuleCollector<MethodRule> collector = new RuleCollector<MethodRule>();
422         getTestClass().collectAnnotatedMethodValues(target, Rule.class, MethodRule.class,
423                 collector);
424         getTestClass().collectAnnotatedFieldValues(target, Rule.class, MethodRule.class,
425                 collector);
426         return collector.result;
427     }
428 
429     /**
430      * @param target the test case instance
431      * @return a list of TestRules that should be applied when executing this
432      *         test
433      */
getTestRules(Object target)434     protected List<TestRule> getTestRules(Object target) {
435         RuleCollector<TestRule> collector = new RuleCollector<TestRule>();
436         getTestClass().collectAnnotatedMethodValues(target, Rule.class, TestRule.class, collector);
437         getTestClass().collectAnnotatedFieldValues(target, Rule.class, TestRule.class, collector);
438         return collector.result;
439     }
440 
getExpectedException(Test annotation)441     private Class<? extends Throwable> getExpectedException(Test annotation) {
442         if (annotation == null || annotation.expected() == None.class) {
443             return null;
444         } else {
445             return annotation.expected();
446         }
447     }
448 
getTimeout(Test annotation)449     private long getTimeout(Test annotation) {
450         if (annotation == null) {
451             return 0;
452         }
453         return annotation.timeout();
454     }
455 
456     private static final ThreadLocal<RuleContainer> CURRENT_RULE_CONTAINER =
457             new ThreadLocal<RuleContainer>();
458 
459     private static class RuleCollector<T> implements MemberValueConsumer<T> {
460         final List<T> result = new ArrayList<T>();
461 
accept(FrameworkMember<?> member, T value)462         public void accept(FrameworkMember<?> member, T value) {
463             Rule rule = member.getAnnotation(Rule.class);
464             if (rule != null) {
465                 RuleContainer container = CURRENT_RULE_CONTAINER.get();
466                 if (container != null) {
467                     container.setOrder(value, rule.order());
468                 }
469             }
470             result.add(value);
471         }
472     }
473 }
474