1 package org.junit.runners; 2 3 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR; 4 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR; 5 6 import java.lang.annotation.Annotation; 7 import java.lang.reflect.Method; 8 import java.util.ArrayList; 9 import java.util.Arrays; 10 import java.util.Collection; 11 import java.util.Collections; 12 import java.util.Comparator; 13 import java.util.Iterator; 14 import java.util.List; 15 16 import org.junit.AfterClass; 17 import org.junit.BeforeClass; 18 import org.junit.ClassRule; 19 import org.junit.Ignore; 20 import org.junit.Rule; 21 import org.junit.internal.AssumptionViolatedException; 22 import org.junit.internal.runners.model.EachTestNotifier; 23 import org.junit.internal.runners.statements.RunAfters; 24 import org.junit.internal.runners.statements.RunBefores; 25 import org.junit.rules.RunRules; 26 import org.junit.rules.TestRule; 27 import org.junit.runner.Description; 28 import org.junit.runner.Runner; 29 import org.junit.runner.manipulation.Filter; 30 import org.junit.runner.manipulation.Filterable; 31 import org.junit.runner.manipulation.NoTestsRemainException; 32 import org.junit.runner.manipulation.Sortable; 33 import org.junit.runner.manipulation.Sorter; 34 import org.junit.runner.notification.RunNotifier; 35 import org.junit.runner.notification.StoppedByUserException; 36 import org.junit.runners.model.FrameworkMethod; 37 import org.junit.runners.model.InitializationError; 38 import org.junit.runners.model.RunnerScheduler; 39 import org.junit.runners.model.Statement; 40 import org.junit.runners.model.TestClass; 41 import org.junit.validator.AnnotationsValidator; 42 import org.junit.validator.PublicClassValidator; 43 import org.junit.validator.TestClassValidator; 44 45 /** 46 * Provides most of the functionality specific to a Runner that implements a 47 * "parent node" in the test tree, with children defined by objects of some data 48 * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is 49 * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses 50 * must implement finding the children of the node, describing each child, and 51 * running each child. ParentRunner will filter and sort children, handle 52 * {@code @BeforeClass} and {@code @AfterClass} methods, 53 * handle annotated {@link ClassRule}s, create a composite 54 * {@link Description}, and run children sequentially. 55 * 56 * @since 4.5 57 */ 58 public abstract class ParentRunner<T> extends Runner implements Filterable, 59 Sortable { 60 private static final List<TestClassValidator> VALIDATORS = Arrays.asList( 61 new AnnotationsValidator(), new PublicClassValidator()); 62 63 private final Object childrenLock = new Object(); 64 private final TestClass testClass; 65 66 // Guarded by childrenLock 67 private volatile Collection<T> filteredChildren = null; 68 69 private volatile RunnerScheduler scheduler = new RunnerScheduler() { 70 public void schedule(Runnable childStatement) { 71 childStatement.run(); 72 } 73 74 public void finished() { 75 // do nothing 76 } 77 }; 78 79 /** 80 * Constructs a new {@code ParentRunner} that will run {@code @TestClass} 81 */ ParentRunner(Class<?> testClass)82 protected ParentRunner(Class<?> testClass) throws InitializationError { 83 this.testClass = createTestClass(testClass); 84 validate(); 85 } 86 createTestClass(Class<?> testClass)87 protected TestClass createTestClass(Class<?> testClass) { 88 return new TestClass(testClass); 89 } 90 91 // 92 // Must be overridden 93 // 94 95 /** 96 * Returns a list of objects that define the children of this Runner. 97 */ getChildren()98 protected abstract List<T> getChildren(); 99 100 /** 101 * Returns a {@link Description} for {@code child}, which can be assumed to 102 * be an element of the list returned by {@link ParentRunner#getChildren()} 103 */ describeChild(T child)104 protected abstract Description describeChild(T child); 105 106 /** 107 * Runs the test corresponding to {@code child}, which can be assumed to be 108 * an element of the list returned by {@link ParentRunner#getChildren()}. 109 * Subclasses are responsible for making sure that relevant test events are 110 * reported through {@code notifier} 111 */ runChild(T child, RunNotifier notifier)112 protected abstract void runChild(T child, RunNotifier notifier); 113 114 // 115 // May be overridden 116 // 117 118 /** 119 * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}). 120 * Default implementation adds an error for each method annotated with 121 * {@code @BeforeClass} or {@code @AfterClass} that is not 122 * {@code public static void} with no arguments. 123 */ collectInitializationErrors(List<Throwable> errors)124 protected void collectInitializationErrors(List<Throwable> errors) { 125 validatePublicVoidNoArgMethods(BeforeClass.class, true, errors); 126 validatePublicVoidNoArgMethods(AfterClass.class, true, errors); 127 validateClassRules(errors); 128 applyValidators(errors); 129 } 130 applyValidators(List<Throwable> errors)131 private void applyValidators(List<Throwable> errors) { 132 if (getTestClass().getJavaClass() != null) { 133 for (TestClassValidator each : VALIDATORS) { 134 errors.addAll(each.validateTestClass(getTestClass())); 135 } 136 } 137 } 138 139 /** 140 * Adds to {@code errors} if any method in this class is annotated with 141 * {@code annotation}, but: 142 * <ul> 143 * <li>is not public, or 144 * <li>takes parameters, or 145 * <li>returns something other than void, or 146 * <li>is static (given {@code isStatic is false}), or 147 * <li>is not static (given {@code isStatic is true}). 148 * </ul> 149 */ validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, boolean isStatic, List<Throwable> errors)150 protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, 151 boolean isStatic, List<Throwable> errors) { 152 List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation); 153 154 for (FrameworkMethod eachTestMethod : methods) { 155 eachTestMethod.validatePublicVoidNoArg(isStatic, errors); 156 } 157 } 158 validateClassRules(List<Throwable> errors)159 private void validateClassRules(List<Throwable> errors) { 160 CLASS_RULE_VALIDATOR.validate(getTestClass(), errors); 161 CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors); 162 } 163 164 /** 165 * Constructs a {@code Statement} to run all of the tests in the test class. 166 * Override to add pre-/post-processing. Here is an outline of the 167 * implementation: 168 * <ol> 169 * <li>Determine the children to be run using {@link #getChildren()} 170 * (subject to any imposed filter and sort).</li> 171 * <li>If there are any children remaining after filtering and ignoring, 172 * construct a statement that will: 173 * <ol> 174 * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li> 175 * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class 176 * and superclasses; if any throws an Exception, stop execution and pass the 177 * exception on.</li> 178 * <li>Run all remaining tests on the test-class.</li> 179 * <li>Run all non-overridden {@code @AfterClass} methods on the test-class 180 * and superclasses: exceptions thrown by previous steps are combined, if 181 * necessary, with exceptions from AfterClass methods into a 182 * {@link org.junit.runners.model.MultipleFailureException}.</li> 183 * </ol> 184 * </li> 185 * </ol> 186 * 187 * @return {@code Statement} 188 */ classBlock(final RunNotifier notifier)189 protected Statement classBlock(final RunNotifier notifier) { 190 Statement statement = childrenInvoker(notifier); 191 if (!areAllChildrenIgnored()) { 192 statement = withBeforeClasses(statement); 193 statement = withAfterClasses(statement); 194 statement = withClassRules(statement); 195 } 196 return statement; 197 } 198 areAllChildrenIgnored()199 private boolean areAllChildrenIgnored() { 200 for (T child : getFilteredChildren()) { 201 if (!isIgnored(child)) { 202 return false; 203 } 204 } 205 return true; 206 } 207 208 /** 209 * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class 210 * and superclasses before executing {@code statement}; if any throws an 211 * Exception, stop execution and pass the exception on. 212 */ withBeforeClasses(Statement statement)213 protected Statement withBeforeClasses(Statement statement) { 214 List<FrameworkMethod> befores = testClass 215 .getAnnotatedMethods(BeforeClass.class); 216 return befores.isEmpty() ? statement : 217 new RunBefores(statement, befores, null); 218 } 219 220 /** 221 * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class 222 * and superclasses before executing {@code statement}; all AfterClass methods are 223 * always executed: exceptions thrown by previous steps are combined, if 224 * necessary, with exceptions from AfterClass methods into a 225 * {@link org.junit.runners.model.MultipleFailureException}. 226 */ withAfterClasses(Statement statement)227 protected Statement withAfterClasses(Statement statement) { 228 List<FrameworkMethod> afters = testClass 229 .getAnnotatedMethods(AfterClass.class); 230 return afters.isEmpty() ? statement : 231 new RunAfters(statement, afters, null); 232 } 233 234 /** 235 * Returns a {@link Statement}: apply all 236 * static fields assignable to {@link TestRule} 237 * annotated with {@link ClassRule}. 238 * 239 * @param statement the base statement 240 * @return a RunRules statement if any class-level {@link Rule}s are 241 * found, or the base statement 242 */ withClassRules(Statement statement)243 private Statement withClassRules(Statement statement) { 244 List<TestRule> classRules = classRules(); 245 return classRules.isEmpty() ? statement : 246 new RunRules(statement, classRules, getDescription()); 247 } 248 249 /** 250 * @return the {@code ClassRule}s that can transform the block that runs 251 * each method in the tested class. 252 */ classRules()253 protected List<TestRule> classRules() { 254 List<TestRule> result = testClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class); 255 result.addAll(testClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class)); 256 return result; 257 } 258 259 /** 260 * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)} 261 * on each object returned by {@link #getChildren()} (subject to any imposed 262 * filter and sort) 263 */ childrenInvoker(final RunNotifier notifier)264 protected Statement childrenInvoker(final RunNotifier notifier) { 265 return new Statement() { 266 @Override 267 public void evaluate() { 268 runChildren(notifier); 269 } 270 }; 271 } 272 273 /** 274 * Evaluates whether a child is ignored. The default implementation always 275 * returns <code>false</code>. 276 * 277 * <p>{@link BlockJUnit4ClassRunner}, for example, overrides this method to 278 * filter tests based on the {@link Ignore} annotation. 279 */ 280 protected boolean isIgnored(T child) { 281 return false; 282 } 283 284 private void runChildren(final RunNotifier notifier) { 285 final RunnerScheduler currentScheduler = scheduler; 286 try { 287 for (final T each : getFilteredChildren()) { 288 currentScheduler.schedule(new Runnable() { 289 public void run() { 290 ParentRunner.this.runChild(each, notifier); 291 } 292 }); 293 } 294 } finally { 295 currentScheduler.finished(); 296 } 297 } 298 299 /** 300 * Returns a name used to describe this Runner 301 */ 302 protected String getName() { 303 return testClass.getName(); 304 } 305 306 // 307 // Available for subclasses 308 // 309 310 /** 311 * Returns a {@link TestClass} object wrapping the class to be executed. 312 */ 313 public final TestClass getTestClass() { 314 return testClass; 315 } 316 317 /** 318 * Runs a {@link Statement} that represents a leaf (aka atomic) test. 319 */ 320 protected final void runLeaf(Statement statement, Description description, 321 RunNotifier notifier) { 322 EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description); 323 eachNotifier.fireTestStarted(); 324 try { 325 statement.evaluate(); 326 } catch (AssumptionViolatedException e) { 327 eachNotifier.addFailedAssumption(e); 328 } catch (Throwable e) { 329 eachNotifier.addFailure(e); 330 } finally { 331 eachNotifier.fireTestFinished(); 332 } 333 } 334 335 /** 336 * @return the annotations that should be attached to this runner's 337 * description. 338 */ 339 protected Annotation[] getRunnerAnnotations() { 340 return testClass.getAnnotations(); 341 } 342 343 // 344 // Implementation of Runner 345 // 346 347 @Override 348 public Description getDescription() { 349 Description description = Description.createSuiteDescription(getName(), 350 getRunnerAnnotations()); 351 for (T child : getFilteredChildren()) { 352 description.addChild(describeChild(child)); 353 } 354 return description; 355 } 356 357 @Override 358 public void run(final RunNotifier notifier) { 359 EachTestNotifier testNotifier = new EachTestNotifier(notifier, 360 getDescription()); 361 try { 362 Statement statement = classBlock(notifier); 363 statement.evaluate(); 364 } catch (AssumptionViolatedException e) { 365 testNotifier.addFailedAssumption(e); 366 } catch (StoppedByUserException e) { 367 throw e; 368 } catch (Throwable e) { 369 testNotifier.addFailure(e); 370 } 371 } 372 373 // 374 // Implementation of Filterable and Sortable 375 // 376 377 public void filter(Filter filter) throws NoTestsRemainException { 378 synchronized (childrenLock) { 379 List<T> children = new ArrayList<T>(getFilteredChildren()); 380 for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) { 381 T each = iter.next(); 382 if (shouldRun(filter, each)) { 383 try { 384 filter.apply(each); 385 } catch (NoTestsRemainException e) { 386 iter.remove(); 387 } 388 } else { 389 iter.remove(); 390 } 391 } 392 filteredChildren = Collections.unmodifiableCollection(children); 393 if (filteredChildren.isEmpty()) { 394 throw new NoTestsRemainException(); 395 } 396 } 397 } 398 399 public void sort(Sorter sorter) { 400 synchronized (childrenLock) { 401 for (T each : getFilteredChildren()) { 402 sorter.apply(each); 403 } 404 List<T> sortedChildren = new ArrayList<T>(getFilteredChildren()); 405 Collections.sort(sortedChildren, comparator(sorter)); 406 filteredChildren = Collections.unmodifiableCollection(sortedChildren); 407 } 408 } 409 410 // 411 // Private implementation 412 // 413 414 private void validate() throws InitializationError { 415 List<Throwable> errors = new ArrayList<Throwable>(); 416 collectInitializationErrors(errors); 417 if (!errors.isEmpty()) { 418 throw new InitializationError(errors); 419 } 420 } 421 422 private Collection<T> getFilteredChildren() { 423 if (filteredChildren == null) { 424 synchronized (childrenLock) { 425 if (filteredChildren == null) { 426 filteredChildren = Collections.unmodifiableCollection(getChildren()); 427 } 428 } 429 } 430 return filteredChildren; 431 } 432 433 private boolean shouldRun(Filter filter, T each) { 434 return filter.shouldRun(describeChild(each)); 435 } 436 437 private Comparator<? super T> comparator(final Sorter sorter) { 438 return new Comparator<T>() { 439 public int compare(T o1, T o2) { 440 return sorter.compare(describeChild(o1), describeChild(o2)); 441 } 442 }; 443 } 444 445 /** 446 * Sets a scheduler that determines the order and parallelization 447 * of children. Highly experimental feature that may change. 448 */ 449 public void setScheduler(RunnerScheduler scheduler) { 450 this.scheduler = scheduler; 451 } 452 } 453