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