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