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.ArrayList;
007 import java.util.List;
008 import java.util.concurrent.ConcurrentHashMap;
009 import java.util.concurrent.ConcurrentMap;
010 import java.util.concurrent.TimeUnit;
011
012 import org.junit.After;
013 import org.junit.Before;
014 import org.junit.Ignore;
015 import org.junit.Rule;
016 import org.junit.Test;
017 import org.junit.Test.None;
018 import org.junit.internal.runners.model.ReflectiveCallable;
019 import org.junit.internal.runners.statements.ExpectException;
020 import org.junit.internal.runners.statements.Fail;
021 import org.junit.internal.runners.statements.FailOnTimeout;
022 import org.junit.internal.runners.statements.InvokeMethod;
023 import org.junit.internal.runners.statements.RunAfters;
024 import org.junit.internal.runners.statements.RunBefores;
025 import org.junit.rules.MethodRule;
026 import org.junit.rules.TestRule;
027 import org.junit.runner.Description;
028 import org.junit.runner.notification.RunNotifier;
029 import org.junit.runners.model.FrameworkMember;
030 import org.junit.runners.model.FrameworkMethod;
031 import org.junit.runners.model.InitializationError;
032 import org.junit.runners.model.MemberValueConsumer;
033 import org.junit.runners.model.MultipleFailureException;
034 import org.junit.runners.model.Statement;
035 import org.junit.runners.model.TestClass;
036 import org.junit.validator.PublicClassValidator;
037 import org.junit.validator.TestClassValidator;
038
039 /**
040 * Implements the JUnit 4 standard test case class model, as defined by the
041 * annotations in the org.junit package. Many users will never notice this
042 * class: it is now the default test class runner, but it should have exactly
043 * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
044 * <p>
045 * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
046 * that are slight changes to the default behavior, however:
047 *
048 * <ul>
049 * <li>It has a much simpler implementation based on {@link Statement}s,
050 * allowing new operations to be inserted into the appropriate point in the
051 * execution flow.
052 *
053 * <li>It is published, and extension and reuse are encouraged, whereas {@code
054 * JUnit4ClassRunner} was in an internal package, and is now deprecated.
055 * </ul>
056 * <p>
057 * In turn, in 2009 we introduced {@link Rule}s. In many cases where extending
058 * BlockJUnit4ClassRunner was necessary to add new behavior, {@link Rule}s can
059 * be used, which makes the extension more reusable and composable.
060 *
061 * @since 4.5
062 */
063 public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
064 private static TestClassValidator PUBLIC_CLASS_VALIDATOR = new PublicClassValidator();
065
066 private final ConcurrentMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>();
067
068 /**
069 * Creates a BlockJUnit4ClassRunner to run {@code testClass}
070 *
071 * @throws InitializationError if the test class is malformed.
072 */
073 public BlockJUnit4ClassRunner(Class<?> testClass) throws InitializationError {
074 super(testClass);
075 }
076
077 /**
078 * Creates a BlockJUnit4ClassRunner to run {@code testClass}.
079 *
080 * @throws InitializationError if the test class is malformed.
081 * @since 4.13
082 */
083 protected BlockJUnit4ClassRunner(TestClass testClass) throws InitializationError {
084 super(testClass);
085 }
086
087 //
088 // Implementation of ParentRunner
089 //
090
091 @Override
092 protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
093 Description description = describeChild(method);
094 if (isIgnored(method)) {
095 notifier.fireTestIgnored(description);
096 } else {
097 Statement statement = new Statement() {
098 @Override
099 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
112 protected boolean isIgnored(FrameworkMethod child) {
113 return child.getAnnotation(Ignore.class) != null;
114 }
115
116 @Override
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
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 */
143 protected List<FrameworkMethod> computeTestMethods() {
144 return getTestClass().getAnnotatedMethods(Test.class);
145 }
146
147 @Override
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
159 private void validatePublicConstructor(List<Throwable> errors) {
160 if (getTestClass().getJavaClass() != null) {
161 errors.addAll(PUBLIC_CLASS_VALIDATOR.validateTestClass(getTestClass()));
162 }
163 }
164
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 */
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 */
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 */
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
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
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
228 protected void validateFields(List<Throwable> errors) {
229 RULE_VALIDATOR.validate(getTestClass(), errors);
230 }
231
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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
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 */
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 */
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
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
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
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 }