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