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