001    package org.junit.runners;
002    
003    import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR;
004    import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR;
005    
006    import java.util.List;
007    import java.util.concurrent.ConcurrentHashMap;
008    import java.util.concurrent.TimeUnit;
009    
010    import org.junit.After;
011    import org.junit.Before;
012    import org.junit.Ignore;
013    import org.junit.Rule;
014    import org.junit.Test;
015    import org.junit.Test.None;
016    import org.junit.internal.runners.model.ReflectiveCallable;
017    import org.junit.internal.runners.statements.ExpectException;
018    import org.junit.internal.runners.statements.Fail;
019    import org.junit.internal.runners.statements.FailOnTimeout;
020    import org.junit.internal.runners.statements.InvokeMethod;
021    import org.junit.internal.runners.statements.RunAfters;
022    import org.junit.internal.runners.statements.RunBefores;
023    import org.junit.rules.MethodRule;
024    import org.junit.rules.RunRules;
025    import org.junit.rules.TestRule;
026    import org.junit.runner.Description;
027    import org.junit.runner.notification.RunNotifier;
028    import org.junit.runners.model.FrameworkMethod;
029    import org.junit.runners.model.InitializationError;
030    import org.junit.runners.model.MultipleFailureException;
031    import org.junit.runners.model.Statement;
032    
033    /**
034     * Implements the JUnit 4 standard test case class model, as defined by the
035     * annotations in the org.junit package. Many users will never notice this
036     * class: it is now the default test class runner, but it should have exactly
037     * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
038     * <p>
039     * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
040     * that are slight changes to the default behavior, however:
041     *
042     * <ul>
043     * <li>It has a much simpler implementation based on {@link Statement}s,
044     * allowing new operations to be inserted into the appropriate point in the
045     * execution flow.
046     *
047     * <li>It is published, and extension and reuse are encouraged, whereas {@code
048     * JUnit4ClassRunner} was in an internal package, and is now deprecated.
049     * </ul>
050     * <p>
051     * In turn, in 2009 we introduced {@link Rule}s.  In many cases where extending
052     * BlockJUnit4ClassRunner was necessary to add new behavior, {@link Rule}s can
053     * be used, which makes the extension more reusable and composable.
054     *
055     * @since 4.5
056     */
057    public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
058        private final ConcurrentHashMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>();
059        /**
060         * Creates a BlockJUnit4ClassRunner to run {@code klass}
061         *
062         * @throws InitializationError if the test class is malformed.
063         */
064        public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
065            super(klass);
066        }
067    
068        //
069        // Implementation of ParentRunner
070        //
071    
072        @Override
073        protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
074            Description description = describeChild(method);
075            if (isIgnored(method)) {
076                notifier.fireTestIgnored(description);
077            } else {
078                runLeaf(methodBlock(method), description, notifier);
079            }
080        }
081        
082        /**
083         * Evaluates whether {@link FrameworkMethod}s are ignored based on the
084         * {@link Ignore} annotation.
085         */
086        @Override
087        protected boolean isIgnored(FrameworkMethod child) {
088            return child.getAnnotation(Ignore.class) != null;
089        }
090    
091        @Override
092        protected Description describeChild(FrameworkMethod method) {
093            Description description = methodDescriptions.get(method);
094    
095            if (description == null) {
096                description = Description.createTestDescription(getTestClass().getJavaClass(),
097                        testName(method), method.getAnnotations());
098                methodDescriptions.putIfAbsent(method, description);
099            }
100    
101            return description;
102        }
103    
104        @Override
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         */
118        protected List<FrameworkMethod> computeTestMethods() {
119            return getTestClass().getAnnotatedMethods(Test.class);
120        }
121    
122        @Override
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    
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         */
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         */
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         */
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    
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
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    
195        protected void validateFields(List<Throwable> errors) {
196            RULE_VALIDATOR.validate(getTestClass(), errors);
197        }
198    
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         */
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         */
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         */
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         */
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         */
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         */
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
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         */
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         */
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    
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    
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    
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         */
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         */
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         */
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    
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    
427        private boolean expectsException(Test annotation) {
428            return getExpectedException(annotation) != null;
429        }
430    
431        private long getTimeout(Test annotation) {
432            if (annotation == null) {
433                return 0;
434            }
435            return annotation.timeout();
436        }
437    }