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