1package org.junit.runners; 2 3import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR; 4 5import java.util.List; 6 7import org.junit.After; 8import org.junit.Before; 9import org.junit.Ignore; 10import org.junit.Rule; 11import org.junit.Test; 12import org.junit.Test.None; 13import org.junit.internal.runners.model.ReflectiveCallable; 14import org.junit.internal.runners.statements.ExpectException; 15import org.junit.internal.runners.statements.Fail; 16import org.junit.internal.runners.statements.FailOnTimeout; 17import org.junit.internal.runners.statements.InvokeMethod; 18import org.junit.internal.runners.statements.RunAfters; 19import org.junit.internal.runners.statements.RunBefores; 20import org.junit.rules.RunRules; 21import org.junit.rules.TestRule; 22import org.junit.runner.Description; 23import org.junit.runner.notification.RunNotifier; 24import org.junit.runners.model.FrameworkMethod; 25import org.junit.runners.model.InitializationError; 26import org.junit.runners.model.MultipleFailureException; 27import 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 */ 47public 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 */ 54 public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError { 55 super(klass); 56 } 57 58 // 59 // Implementation of ParentRunner 60 // 61 62 @Override 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 73 protected Description describeChild(FrameworkMethod method) { 74 return Description.createTestDescription(getTestClass().getJavaClass(), 75 testName(method), method.getAnnotations()); 76 } 77 78 @Override 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 */ 92 protected List<FrameworkMethod> computeTestMethods() { 93 return getTestClass().getAnnotatedMethods(Test.class); 94 } 95 96 @Override 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 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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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") 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") 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 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 */ 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 */ 386 protected List<TestRule> getTestRules(Object target) { 387 return getTestClass().getAnnotatedFieldValues(target, 388 Rule.class, TestRule.class); 389 } 390 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 398 private boolean expectsException(Test annotation) { 399 return getExpectedException(annotation) != null; 400 } 401 402 private long getTimeout(Test annotation) { 403 if (annotation == null) 404 return 0; 405 return annotation.timeout(); 406 } 407} 408