001/* 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.kuali.rice.test.runners; 018 019import org.apache.commons.beanutils.MethodUtils; 020import org.junit.After; 021import org.junit.AfterClass; 022import org.junit.Before; 023import org.junit.BeforeClass; 024import org.junit.ClassRule; 025import org.junit.Ignore; 026import org.junit.Rule; 027import org.junit.Test; 028import org.junit.internal.AssumptionViolatedException; 029import org.junit.internal.runners.model.EachTestNotifier; 030import org.junit.internal.runners.model.ReflectiveCallable; 031import org.junit.internal.runners.statements.ExpectException; 032import org.junit.internal.runners.statements.Fail; 033import org.junit.internal.runners.statements.FailOnTimeout; 034import org.junit.internal.runners.statements.InvokeMethod; 035import org.junit.internal.runners.statements.RunAfters; 036import org.junit.internal.runners.statements.RunBefores; 037import org.junit.rules.RunRules; 038import org.junit.rules.TestRule; 039import org.junit.runner.Description; 040import org.junit.runner.JUnitCore; 041import org.junit.runner.Result; 042import org.junit.runner.RunWith; 043import org.junit.runner.Runner; 044import org.junit.runner.manipulation.Filter; 045import org.junit.runner.manipulation.Filterable; 046import org.junit.runner.manipulation.NoTestsRemainException; 047import org.junit.runner.manipulation.Sortable; 048import org.junit.runner.manipulation.Sorter; 049import org.junit.runner.notification.Failure; 050import org.junit.runner.notification.RunNotifier; 051import org.junit.runner.notification.StoppedByUserException; 052import org.junit.runners.model.FrameworkMethod; 053import org.junit.runners.model.InitializationError; 054import org.junit.runners.model.RunnerScheduler; 055import org.junit.runners.model.Statement; 056import org.junit.runners.model.TestClass; 057import org.kuali.rice.core.api.util.ShadowingInstrumentableClassLoader; 058import org.kuali.rice.test.MethodAware; 059 060import java.lang.annotation.Annotation; 061import java.lang.reflect.Method; 062import java.util.ArrayList; 063import java.util.Collections; 064import java.util.Comparator; 065import java.util.Iterator; 066import java.util.List; 067 068import static org.junit.internal.runners.rules.RuleFieldValidator.*; 069 070/** 071 * A JUnit test {@link org.junit.runner.Runner} which uses a custom classloader with a copy of the classpath and allows 072 * for transformers to be added to the ClassLoader for load-time weaving. 073 * 074 * <p>Useful when writing tests that use JPA with EclipseLink since it depends upon load-time weaving.</p> 075 * 076 * <p>In order to use this class, you must have a {@link BootstrapTest} annotation available somewhere in the hierarchy 077 * of your test class (usually on the same class where the {@link RunWith} annotation is specified which references this 078 * runner class). This informs the runner about a test that it can run to execute any one-time initialization for 079 * the test suite. Ideally, this bootstrap test will execute code which loads JPA persistence units and any associated 080 * ClassFileTransformers for load-time weaving. This is necessary because it is common for an integration test to have 081 * references in the test class itself to JPA entities which need to be weaved. When this occurs, if the persistence 082 * units and ClassFileTransformers are not properly loaded before the entity classes are loaded by the classloader, then 083 * instrumentation will (silently!) fail to occur.</p> 084 * 085 * <p>Much of the code in this class was copied from the JUnit ParentRunner, BlockJUnit4ClassRunner, and 086 * TomcatInstrumentableClassLoader.</p> 087 * 088 * @author Kuali Rice Team (rice.collab@kuali.org) 089 */ 090public class LoadTimeWeavableTestRunner extends Runner implements Filterable, Sortable { 091 092 private static final String[] JUNIT_CLASSLOADER_EXCLUDES = { "org.junit.", "junit.framework." }; 093 094 private final TestClass originalTestClass; 095 private TestClass fTestClass; 096 private Method currentMethod; 097 098 // static because we only need one custom loader per JVM in which the tests are running, otherwise the memory 099 // usage gets crazy! 100 private static ClassLoader customLoader; 101 102 private Sorter fSorter = Sorter.NULL; 103 104 private List<FrameworkMethod> originalFilteredChildren = null; 105 private List<FrameworkMethod> filteredChildren = null; 106 107 private static final ThreadLocal<Boolean> runningBootstrapTest = new ThreadLocal<Boolean>() { 108 @Override 109 protected Boolean initialValue() { 110 return Boolean.FALSE; 111 } 112 }; 113 114 private RunnerScheduler fScheduler = new RunnerScheduler() { 115 public void schedule(Runnable childStatement) { 116 childStatement.run(); 117 } 118 public void finished() { 119 // do nothing 120 } 121 }; 122 123 /** 124 * Constructs a new {@code ParentRunner} that will run {@code @TestClass} 125 */ 126 public LoadTimeWeavableTestRunner(Class<?> testClass) throws InitializationError { 127 this.originalTestClass = new TestClass(testClass); 128 if (LoadTimeWeavableTestRunner.customLoader == null) { 129 LoadTimeWeavableTestRunner.customLoader = 130 new ShadowingInstrumentableClassLoader(testClass.getClassLoader(), JUNIT_CLASSLOADER_EXCLUDES); 131 } 132 validate(); 133 } 134 135 private TestClass getCustomTestClass(Class<?> originalTestClass, ClassLoader customLoader) { 136 try { 137 Class<?> newTestClass = customLoader.loadClass(originalTestClass.getName()); 138 if (newTestClass == originalTestClass) { 139 throw new IllegalStateException(newTestClass.getName() + " loaded from custom class loader should have been a different instance but was the same!"); 140 } 141 return new TestClass(newTestClass); 142 } catch (ClassNotFoundException e) { 143 throw new IllegalStateException("Failed to load test class from custom classloader: " + originalTestClass.getName()); 144 } 145 } 146 147 protected ClassLoader getCustomClassLoader() { 148 return customLoader; 149 } 150 151 /** 152 * Adds to {@code errors} if any method in this class is annotated with 153 * {@code annotation}, but: 154 * <ul> 155 * <li>is not public, or 156 * <li>takes parameters, or 157 * <li>returns something other than void, or 158 * <li>is static (given {@code isStatic is false}), or 159 * <li>is not static (given {@code isStatic is true}). 160 */ 161 protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, 162 boolean isStatic, List<Throwable> errors) { 163 List<FrameworkMethod> methods = getOriginalTestClass().getAnnotatedMethods(annotation); 164 165 for (FrameworkMethod eachTestMethod : methods) { 166 eachTestMethod.validatePublicVoidNoArg(isStatic, errors); 167 } 168 } 169 170 private void validateClassRules(List<Throwable> errors) { 171 CLASS_RULE_VALIDATOR.validate(getOriginalTestClass(), errors); 172 CLASS_RULE_METHOD_VALIDATOR.validate(getOriginalTestClass(), errors); 173 } 174 175 /** 176 * Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing. 177 * Here is an outline of the implementation: 178 * <ul> 179 * <li>Call {@link #runChild(org.junit.runners.model.FrameworkMethod, org.junit.runner.notification.RunNotifier)} on each object returned by {@link #getChildren()} (subject to any imposed filter and sort).</li> 180 * <li>ALWAYS run all non-overridden {@code @BeforeClass} methods on this class 181 * and superclasses before the previous step; if any throws an 182 * Exception, stop execution and pass the exception on. 183 * <li>ALWAYS run all non-overridden {@code @AfterClass} methods on this class 184 * and superclasses before any of the previous steps; all AfterClass methods are 185 * always executed: exceptions thrown by previous steps are combined, if 186 * necessary, with exceptions from AfterClass methods into a 187 * {@link org.junit.runners.model.MultipleFailureException}. 188 * </ul> 189 * 190 * @return {@code Statement} 191 */ 192 protected Statement classBlock(final RunNotifier notifier) { 193 Statement statement = childrenInvoker(notifier); 194 statement = withBeforeClasses(statement); 195 statement = withAfterClasses(statement); 196 statement = withClassRules(statement); 197 return statement; 198 } 199 200 /** 201 * Returns a {@link org.junit.runners.model.Statement}: run all non-overridden {@code @BeforeClass} methods on this class 202 * and superclasses before executing {@code statement}; if any throws an 203 * Exception, stop execution and pass the exception on. 204 */ 205 protected Statement withBeforeClasses(Statement statement) { 206 List<FrameworkMethod> befores = getTestClass() 207 .getAnnotatedMethods(BeforeClass.class); 208 return befores.isEmpty() ? statement : 209 new RunBefores(statement, befores, null); 210 } 211 212 /** 213 * Returns a {@link org.junit.runners.model.Statement}: run all non-overridden {@code @AfterClass} methods on this class 214 * and superclasses before executing {@code statement}; all AfterClass methods are 215 * always executed: exceptions thrown by previous steps are combined, if 216 * necessary, with exceptions from AfterClass methods into a 217 * {@link org.junit.runners.model.MultipleFailureException}. 218 */ 219 protected Statement withAfterClasses(Statement statement) { 220 List<FrameworkMethod> afters = getTestClass() 221 .getAnnotatedMethods(AfterClass.class); 222 return afters.isEmpty() ? statement : 223 new RunAfters(statement, afters, null); 224 } 225 226 /** 227 * Returns a {@link org.junit.runners.model.Statement}: apply all 228 * static fields assignable to {@link org.junit.rules.TestRule} 229 * annotated with {@link org.junit.ClassRule}. 230 * 231 * @param statement the base statement 232 * @return a RunRules statement if any class-level {@link org.junit.Rule}s are 233 * found, or the base statement 234 */ 235 private Statement withClassRules(Statement statement) { 236 List<TestRule> classRules = classRules(); 237 return classRules.isEmpty() ? statement : 238 new RunRules(statement, classRules, getDescription()); 239 } 240 241 /** 242 * @return the {@code ClassRule}s that can transform the block that runs 243 * each method in the tested class. 244 */ 245 protected List<TestRule> classRules() { 246 List<TestRule> result = getTestClass().getAnnotatedMethodValues(null, ClassRule.class, TestRule.class); 247 248 result.addAll(getTestClass().getAnnotatedFieldValues(null, ClassRule.class, TestRule.class)); 249 250 return result; 251 } 252 253 /** 254 * Returns a {@link org.junit.runners.model.Statement}: Call {@link #runChild(org.junit.runners.model.FrameworkMethod, org.junit.runner.notification.RunNotifier)} 255 * on each object returned by {@link #getChildren()} (subject to any imposed 256 * filter and sort) 257 */ 258 protected Statement childrenInvoker(final RunNotifier notifier) { 259 return new Statement() { 260 @Override 261 public void evaluate() { 262 runChildren(notifier); 263 } 264 }; 265 } 266 267 private void runChildren(final RunNotifier notifier) { 268 for (final FrameworkMethod each : getFilteredChildren()) { 269 fScheduler.schedule(new Runnable() { 270 public void run() { 271 LoadTimeWeavableTestRunner.this.runChild(each, notifier); 272 } 273 }); 274 } 275 fScheduler.finished(); 276 } 277 278 /** 279 * Returns a name used to describe this Runner 280 */ 281 protected String getName() { 282 return getOriginalTestClass().getName(); 283 } 284 285 /** 286 * Returns a {@link org.junit.runners.model.TestClass} object wrapping the class to be executed. 287 */ 288 public final TestClass getTestClass() { 289 if (fTestClass == null) { 290 throw new IllegalStateException("Attempted to access test class but it has not yet been initialized!"); 291 } 292 return fTestClass; 293 } 294 295 /** 296 * Returns the original test class that was passed to this test runner. 297 */ 298 public final TestClass getOriginalTestClass() { 299 return originalTestClass; 300 } 301 302 /** 303 * Runs a {@link org.junit.runners.model.Statement} that represents a leaf (aka atomic) test. 304 */ 305 protected final void runLeaf(Statement statement, Description description, 306 RunNotifier notifier) { 307 EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description); 308 eachNotifier.fireTestStarted(); 309 try { 310 statement.evaluate(); 311 } catch (AssumptionViolatedException e) { 312 eachNotifier.addFailedAssumption(e); 313 } catch (Throwable e) { 314 eachNotifier.addFailure(e); 315 } finally { 316 eachNotifier.fireTestFinished(); 317 } 318 } 319 320 /** 321 * @return the annotations that should be attached to this runner's 322 * description. 323 */ 324 protected Annotation[] getRunnerAnnotations() { 325 return getOriginalTestClass().getAnnotations(); 326 } 327 328 // 329 // Implementation of Runner 330 // 331 332 @Override 333 public Description getDescription() { 334 Description description = Description.createSuiteDescription(getName(), 335 getRunnerAnnotations()); 336 for (FrameworkMethod child : getOriginalFilteredChildren()) { 337 description.addChild(describeOriginalChild(child)); 338 } 339 return description; 340 } 341 342 @Override 343 public void run(final RunNotifier notifier) { 344 ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader(); 345 Thread.currentThread().setContextClassLoader(customLoader); 346 try { 347 if (runBootstrapTest(notifier, getOriginalTestClass())) { 348 this.fTestClass = getCustomTestClass(getOriginalTestClass().getJavaClass(), customLoader); 349 EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription()); 350 try { 351 Statement statement = classBlock(notifier); 352 statement.evaluate(); 353 } catch (AssumptionViolatedException e) { 354 testNotifier.fireTestIgnored(); 355 } catch (StoppedByUserException e) { 356 throw e; 357 } catch (Throwable e) { 358 testNotifier.addFailure(e); 359 } 360 } 361 } finally { 362 Thread.currentThread().setContextClassLoader(currentContextClassLoader); 363 } 364 } 365 366 protected boolean runBootstrapTest(RunNotifier notifier, TestClass testClass) { 367 if (!runningBootstrapTest.get().booleanValue()) { 368 runningBootstrapTest.set(Boolean.TRUE); 369 try { 370 BootstrapTest bootstrapTest = getBootstrapTestAnnotation(testClass.getJavaClass()); 371 if (bootstrapTest != null) { 372 Result result = JUnitCore.runClasses(bootstrapTest.value()); 373 List<Failure> failures = result.getFailures(); 374 for (Failure failure : failures) { 375 notifier.fireTestFailure(failure); 376 } 377 return result.getFailureCount() == 0; 378 } else { 379 throw new IllegalStateException("LoadTimeWeavableTestRunner, must be coupled with an @BootstrapTest annotation to define the bootstrap test to execute."); 380 } 381 } finally { 382 runningBootstrapTest.set(Boolean.FALSE); 383 } 384 } 385 return true; 386 } 387 388 private BootstrapTest getBootstrapTestAnnotation(Class<?> testClass) { 389 BootstrapTest bootstrapTest = testClass.getAnnotation(BootstrapTest.class); 390 if (bootstrapTest != null) { 391 return bootstrapTest; 392 } else if (testClass.getSuperclass() != null) { 393 return getBootstrapTestAnnotation(testClass.getSuperclass()); 394 } else { 395 return null; 396 } 397 } 398 399 // 400 // Implementation of Filterable and Sortable 401 // 402 403 public void filter(Filter filter) throws NoTestsRemainException { 404 for (Iterator<FrameworkMethod> iter = getOriginalFilteredChildren().iterator(); iter.hasNext(); ) { 405 FrameworkMethod each = iter.next(); 406 if (shouldRun(filter, each)) { 407 try { 408 filter.apply(each); 409 } catch (NoTestsRemainException e) { 410 iter.remove(); 411 } 412 } else { 413 iter.remove(); 414 } 415 } 416 if (getOriginalFilteredChildren().isEmpty()) { 417 throw new NoTestsRemainException(); 418 } 419 } 420 421 public void sort(Sorter sorter) { 422 fSorter = sorter; 423 for (FrameworkMethod each : getOriginalFilteredChildren()) { 424 sortChild(each); 425 } 426 Collections.sort(getOriginalFilteredChildren(), comparator()); 427 } 428 429 // 430 // Private implementation 431 // 432 433 private void validate() throws InitializationError { 434 List<Throwable> errors = new ArrayList<Throwable>(); 435 collectInitializationErrors(errors); 436 if (!errors.isEmpty()) { 437 throw new InitializationError(errors); 438 } 439 } 440 441 private List<FrameworkMethod> getOriginalFilteredChildren() { 442 if (originalFilteredChildren == null) { 443 originalFilteredChildren = new ArrayList<FrameworkMethod>(getOriginalChildren()); 444 } 445 return originalFilteredChildren; 446 } 447 448 private List<FrameworkMethod> getFilteredChildren() { 449 if (getOriginalFilteredChildren() == null) { 450 throw new IllegalStateException("Attempted to get filtered children before original filtered children were initialized."); 451 } 452 if (filteredChildren == null) { 453 filteredChildren = new ArrayList<FrameworkMethod>(); 454 List<FrameworkMethod> testMethods = computeTestMethods(); 455 for (FrameworkMethod originalMethod : getOriginalFilteredChildren()) { 456 for (FrameworkMethod testMethod : testMethods) { 457 if (originalMethod.isShadowedBy(testMethod)) { 458 filteredChildren.add(testMethod); 459 } 460 } 461 } 462 } 463 return filteredChildren; 464 } 465 466 private void sortChild(FrameworkMethod child) { 467 fSorter.apply(child); 468 } 469 470 private boolean shouldRun(Filter filter, FrameworkMethod each) { 471 return filter.shouldRun(describeOriginalChild(each)); 472 } 473 474 private Comparator<? super FrameworkMethod> comparator() { 475 return new Comparator<FrameworkMethod>() { 476 public int compare(FrameworkMethod o1, FrameworkMethod o2) { 477 return fSorter.compare(describeChild(o1), describeChild(o2)); 478 } 479 }; 480 } 481 482 // 483 // Implementation of ParentRunner 484 // 485 486 /** 487 * Runs the test corresponding to {@code child}, which can be assumed to be 488 * an element of the list returned by {@link #getChildren()}. 489 * Subclasses are responsible for making sure that relevant test events are 490 * reported through {@code notifier} 491 */ 492 protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 493 this.currentMethod = method.getMethod(); 494 try { 495 Description description = describeChild(method); 496 if (method.getAnnotation(Ignore.class) != null) { 497 notifier.fireTestIgnored(description); 498 } else { 499 runLeaf(methodBlock(method), description, notifier); 500 } 501 } finally { 502 this.currentMethod = null; 503 } 504 } 505 506 /** 507 * Returns a {@link org.junit.runner.Description} for {@code child}, which can be assumed to 508 * be an element of the list returned by {@link #getChildren()} 509 */ 510 protected Description describeChild(FrameworkMethod method) { 511 return Description.createTestDescription(getTestClass().getJavaClass(), 512 testName(method), method.getAnnotations()); 513 } 514 515 protected Description describeOriginalChild(FrameworkMethod method) { 516 return Description.createTestDescription(getOriginalTestClass().getJavaClass(), 517 testName(method), method.getAnnotations()); 518 } 519 520 /** 521 * Returns a list of objects that define the children of this Runner. 522 */ 523 protected List<FrameworkMethod> getChildren() { 524 return computeTestMethods(); 525 } 526 527 protected List<FrameworkMethod> getOriginalChildren() { 528 return computeOriginalTestMethods(); 529 } 530 531 // 532 // Override in subclasses 533 // 534 535 /** 536 * Returns the methods that run tests. Default implementation returns all 537 * methods annotated with {@code @Test} on this class and superclasses that 538 * are not overridden. 539 */ 540 protected List<FrameworkMethod> computeTestMethods() { 541 return getTestClass().getAnnotatedMethods(Test.class); 542 } 543 544 protected List<FrameworkMethod> computeOriginalTestMethods() { 545 return getOriginalTestClass().getAnnotatedMethods(Test.class); 546 } 547 548 /** 549 * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}). 550 * Default implementation adds an error for each method annotated with 551 * {@code @BeforeClass} or {@code @AfterClass} that is not 552 * {@code public static void} with no arguments. 553 */ 554 protected void collectInitializationErrors(List<Throwable> errors) { 555 validatePublicVoidNoArgMethods(BeforeClass.class, true, errors); 556 validatePublicVoidNoArgMethods(AfterClass.class, true, errors); 557 validateClassRules(errors); 558 validateNoNonStaticInnerClass(errors); 559 validateConstructor(errors); 560 validateInstanceMethods(errors); 561 validateFields(errors); 562 validateMethods(errors); 563 } 564 565 protected void validateNoNonStaticInnerClass(List<Throwable> errors) { 566 if (getOriginalTestClass().isANonStaticInnerClass()) { 567 String gripe = "The inner class " + getOriginalTestClass().getName() 568 + " is not static."; 569 errors.add(new Exception(gripe)); 570 } 571 } 572 573 /** 574 * Adds to {@code errors} if the test class has more than one constructor, 575 * or if the constructor takes parameters. Override if a subclass requires 576 * different validation rules. 577 */ 578 protected void validateConstructor(List<Throwable> errors) { 579 validateOnlyOneConstructor(errors); 580 validateZeroArgConstructor(errors); 581 } 582 583 /** 584 * Adds to {@code errors} if the test class has more than one constructor 585 * (do not override) 586 */ 587 protected void validateOnlyOneConstructor(List<Throwable> errors) { 588 if (!hasOneConstructor()) { 589 String gripe = "Test class should have exactly one public constructor"; 590 errors.add(new Exception(gripe)); 591 } 592 } 593 594 /** 595 * Adds to {@code errors} if the test class's single constructor takes 596 * parameters (do not override) 597 */ 598 protected void validateZeroArgConstructor(List<Throwable> errors) { 599 if (!getOriginalTestClass().isANonStaticInnerClass() 600 && hasOneConstructor() 601 && (getOriginalTestClass().getOnlyConstructor().getParameterTypes().length != 0)) { 602 String gripe = "Test class should have exactly one public zero-argument constructor"; 603 errors.add(new Exception(gripe)); 604 } 605 } 606 607 private boolean hasOneConstructor() { 608 return getOriginalTestClass().getJavaClass().getConstructors().length == 1; 609 } 610 611 /** 612 * Adds to {@code errors} for each method annotated with {@code @Test}, 613 * {@code @Before}, or {@code @After} that is not a public, void instance 614 * method with no arguments. 615 * 616 * @deprecated unused API, will go away in future version 617 */ 618 @Deprecated 619 protected void validateInstanceMethods(List<Throwable> errors) { 620 validatePublicVoidNoArgMethods(After.class, false, errors); 621 validatePublicVoidNoArgMethods(Before.class, false, errors); 622 validateTestMethods(errors); 623 624 if (computeOriginalTestMethods().size() == 0) { 625 errors.add(new Exception("No runnable methods")); 626 } 627 } 628 629 protected void validateFields(List<Throwable> errors) { 630 RULE_VALIDATOR.validate(getOriginalTestClass(), errors); 631 } 632 633 private void validateMethods(List<Throwable> errors) { 634 RULE_METHOD_VALIDATOR.validate(getOriginalTestClass(), errors); 635 } 636 637 /** 638 * Adds to {@code errors} for each method annotated with {@code @Test}that 639 * is not a public, void instance method with no arguments. 640 */ 641 protected void validateTestMethods(List<Throwable> errors) { 642 validatePublicVoidNoArgMethods(Test.class, false, errors); 643 } 644 645 /** 646 * Returns a new fixture for running a test. Default implementation executes 647 * the test class's no-argument constructor (validation should have ensured 648 * one exists). 649 */ 650 protected Object createTest() throws Exception { 651 Object test = getTestClass().getOnlyConstructor().newInstance(); 652 setTestName(test, currentMethod); 653 setTestMethod(test, currentMethod); 654 return test; 655 } 656 657 /** 658 * Sets the {@link java.lang.reflect.Method} on the test case if it is {@link org.kuali.rice.test.MethodAware} 659 * @param method the current method to be run 660 * @param test the test instance 661 */ 662 protected void setTestMethod(Object test, Method method) throws Exception { 663 Class<?> methodAwareClass = Class.forName(MethodAware.class.getName(), true, getCustomClassLoader()); 664 if (methodAwareClass.isInstance(test)) { 665 Method setTestMethod = methodAwareClass.getMethod("setTestMethod", Method.class); 666 setTestMethod.invoke(test, method); 667 } 668 } 669 670 protected void setTestName(final Object test, final Method testMethod) throws Exception { 671 String name = testMethod == null ? "" : testMethod.getName(); 672 final Method setNameMethod = MethodUtils.getAccessibleMethod(test.getClass(), "setName", 673 new Class[]{String.class}); 674 if (setNameMethod != null) { 675 setNameMethod.invoke(test, name); 676 } 677 } 678 679 /** 680 * Returns the name that describes {@code method} for {@link org.junit.runner.Description}s. 681 * Default implementation is the method's name 682 */ 683 protected String testName(FrameworkMethod method) { 684 return method.getName(); 685 } 686 687 /** 688 * Returns a Statement that, when executed, either returns normally if 689 * {@code method} passes, or throws an exception if {@code method} fails. 690 * 691 * Here is an outline of the default implementation: 692 * 693 * <ul> 694 * <li>Invoke {@code method} on the result of {@code createTest()}, and 695 * throw any exceptions thrown by either operation. 696 * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code 697 * expecting} attribute, return normally only if the previous step threw an 698 * exception of the correct type, and throw an exception otherwise. 699 * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code 700 * timeout} attribute, throw an exception if the previous step takes more 701 * than the specified number of milliseconds. 702 * <li>ALWAYS run all non-overridden {@code @Before} methods on this class 703 * and superclasses before any of the previous steps; if any throws an 704 * Exception, stop execution and pass the exception on. 705 * <li>ALWAYS run all non-overridden {@code @After} methods on this class 706 * and superclasses after any of the previous steps; all After methods are 707 * always executed: exceptions thrown by previous steps are combined, if 708 * necessary, with exceptions from After methods into a 709 * {@link org.junit.runners.model.MultipleFailureException}. 710 * <li>ALWAYS allow {@code @Rule} fields to modify the execution of the 711 * above steps. A {@code Rule} may prevent all execution of the above steps, 712 * or add additional behavior before and after, or modify thrown exceptions. 713 * For more information, see {@link org.junit.rules.TestRule} 714 * </ul> 715 * 716 * This can be overridden in subclasses, either by overriding this method, 717 * or the implementations creating each sub-statement. 718 */ 719 protected Statement methodBlock(FrameworkMethod method) { 720 Object test; 721 try { 722 test = new ReflectiveCallable() { 723 @Override 724 protected Object runReflectiveCall() throws Throwable { 725 return createTest(); 726 } 727 }.run(); 728 } catch (Throwable e) { 729 return new Fail(e); 730 } 731 732 Statement statement = methodInvoker(method, test); 733 statement = possiblyExpectingExceptions(method, test, statement); 734 statement = withPotentialTimeout(method, test, statement); 735 statement = withBefores(method, test, statement); 736 statement = withAfters(method, test, statement); 737 statement = withRules(method, test, statement); 738 return statement; 739 } 740 741 // 742 // Statement builders 743 // 744 745 /** 746 * Returns a {@link org.junit.runners.model.Statement} that invokes {@code method} on {@code test} 747 */ 748 protected Statement methodInvoker(FrameworkMethod method, Object test) { 749 return new InvokeMethod(method, test); 750 } 751 752 /** 753 * Returns a {@link org.junit.runners.model.Statement}: if {@code method}'s {@code @Test} annotation 754 * has the {@code expecting} attribute, return normally only if {@code next} 755 * throws an exception of the correct type, and throw an exception 756 * otherwise. 757 * 758 * @deprecated Will be private soon: use Rules instead 759 */ 760 @Deprecated 761 protected Statement possiblyExpectingExceptions(FrameworkMethod method, 762 Object test, Statement next) { 763 Test annotation = method.getAnnotation(Test.class); 764 return expectsException(annotation) ? new ExpectException(next, 765 getExpectedException(annotation)) : next; 766 } 767 768 /** 769 * Returns a {@link org.junit.runners.model.Statement}: if {@code method}'s {@code @Test} annotation 770 * has the {@code timeout} attribute, throw an exception if {@code next} 771 * takes more than the specified number of milliseconds. 772 * 773 * @deprecated Will be private soon: use Rules instead 774 */ 775 @Deprecated 776 protected Statement withPotentialTimeout(FrameworkMethod method, 777 Object test, Statement next) { 778 long timeout = getTimeout(method.getAnnotation(Test.class)); 779 return timeout > 0 ? new FailOnTimeout(next, timeout) : next; 780 } 781 782 /** 783 * Returns a {@link org.junit.runners.model.Statement}: run all non-overridden {@code @Before} 784 * methods on this class and superclasses before running {@code next}; if 785 * any throws an Exception, stop execution and pass the exception on. 786 * 787 * @deprecated Will be private soon: use Rules instead 788 */ 789 @Deprecated 790 protected Statement withBefores(FrameworkMethod method, Object target, 791 Statement statement) { 792 List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(Before.class); 793 return befores.isEmpty() ? statement : new RunBefores(statement, 794 befores, target); 795 } 796 797 /** 798 * Returns a {@link org.junit.runners.model.Statement}: run all non-overridden {@code @After} 799 * methods on this class and superclasses before running {@code next}; all 800 * After methods are always executed: exceptions thrown by previous steps 801 * are combined, if necessary, with exceptions from After methods into a 802 * {@link org.junit.runners.model.MultipleFailureException}. 803 * 804 * @deprecated Will be private soon: use Rules instead 805 */ 806 @Deprecated 807 protected Statement withAfters(FrameworkMethod method, Object target, 808 Statement statement) { 809 List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods( 810 After.class); 811 return afters.isEmpty() ? statement : new RunAfters(statement, afters, 812 target); 813 } 814 815 private Statement withRules(FrameworkMethod method, Object target, 816 Statement statement) { 817 List<TestRule> testRules = getTestRules(target); 818 Statement result = statement; 819 result = withMethodRules(method, testRules, target, result); 820 result = withTestRules(method, testRules, result); 821 822 return result; 823 } 824 825 private Statement withMethodRules(FrameworkMethod method, List<TestRule> testRules, 826 Object target, Statement result) { 827 for (org.junit.rules.MethodRule each : getMethodRules(target)) { 828 if (!testRules.contains(each)) { 829 result = each.apply(result, method, target); 830 } 831 } 832 return result; 833 } 834 835 private List<org.junit.rules.MethodRule> getMethodRules(Object target) { 836 return rules(target); 837 } 838 839 /** 840 * @param target the test case instance 841 * @return a list of MethodRules that should be applied when executing this 842 * test 843 */ 844 protected List<org.junit.rules.MethodRule> rules(Object target) { 845 return getTestClass().getAnnotatedFieldValues(target, Rule.class, org.junit.rules.MethodRule.class); 846 } 847 848 /** 849 * Returns a {@link org.junit.runners.model.Statement}: apply all non-static value fields 850 * annotated with {@link org.junit.Rule}. 851 * 852 * @param statement The base statement 853 * @return a RunRules statement if any class-level {@link org.junit.Rule}s are 854 * found, or the base statement 855 */ 856 private Statement withTestRules(FrameworkMethod method, List<TestRule> testRules, 857 Statement statement) { 858 return testRules.isEmpty() ? statement : 859 new RunRules(statement, testRules, describeChild(method)); 860 } 861 862 /** 863 * @param target the test case instance 864 * @return a list of TestRules that should be applied when executing this 865 * test 866 */ 867 protected List<TestRule> getTestRules(Object target) { 868 List<TestRule> result = getTestClass().getAnnotatedMethodValues(target, 869 Rule.class, TestRule.class); 870 871 result.addAll(getTestClass().getAnnotatedFieldValues(target, 872 Rule.class, TestRule.class)); 873 874 return result; 875 } 876 877 private Class<? extends Throwable> getExpectedException(Test annotation) { 878 if (annotation == null || annotation.expected() == Test.None.class) { 879 return null; 880 } else { 881 return annotation.expected(); 882 } 883 } 884 885 private boolean expectsException(Test annotation) { 886 return getExpectedException(annotation) != null; 887 } 888 889 private long getTimeout(Test annotation) { 890 if (annotation == null) { 891 return 0; 892 } 893 return annotation.timeout(); 894 } 895 896}