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