View Javadoc
1   /*
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.kuali.rice.test.runners;
18  
19  import org.apache.commons.beanutils.MethodUtils;
20  import org.junit.After;
21  import org.junit.AfterClass;
22  import org.junit.Before;
23  import org.junit.BeforeClass;
24  import org.junit.ClassRule;
25  import org.junit.Ignore;
26  import org.junit.Rule;
27  import org.junit.Test;
28  import org.junit.internal.AssumptionViolatedException;
29  import org.junit.internal.runners.model.EachTestNotifier;
30  import org.junit.internal.runners.model.ReflectiveCallable;
31  import org.junit.internal.runners.statements.ExpectException;
32  import org.junit.internal.runners.statements.Fail;
33  import org.junit.internal.runners.statements.FailOnTimeout;
34  import org.junit.internal.runners.statements.InvokeMethod;
35  import org.junit.internal.runners.statements.RunAfters;
36  import org.junit.internal.runners.statements.RunBefores;
37  import org.junit.rules.RunRules;
38  import org.junit.rules.TestRule;
39  import org.junit.runner.Description;
40  import org.junit.runner.JUnitCore;
41  import org.junit.runner.Result;
42  import org.junit.runner.RunWith;
43  import org.junit.runner.Runner;
44  import org.junit.runner.manipulation.Filter;
45  import org.junit.runner.manipulation.Filterable;
46  import org.junit.runner.manipulation.NoTestsRemainException;
47  import org.junit.runner.manipulation.Sortable;
48  import org.junit.runner.manipulation.Sorter;
49  import org.junit.runner.notification.Failure;
50  import org.junit.runner.notification.RunNotifier;
51  import org.junit.runner.notification.StoppedByUserException;
52  import org.junit.runners.model.FrameworkMethod;
53  import org.junit.runners.model.InitializationError;
54  import org.junit.runners.model.RunnerScheduler;
55  import org.junit.runners.model.Statement;
56  import org.junit.runners.model.TestClass;
57  import org.kuali.rice.core.api.util.ShadowingInstrumentableClassLoader;
58  import org.kuali.rice.test.MethodAware;
59  
60  import java.lang.annotation.Annotation;
61  import java.lang.reflect.Method;
62  import java.util.ArrayList;
63  import java.util.Collections;
64  import java.util.Comparator;
65  import java.util.Iterator;
66  import java.util.List;
67  
68  import static org.junit.internal.runners.rules.RuleFieldValidator.*;
69  
70  /**
71   * A JUnit test {@link org.junit.runner.Runner} which uses a custom classloader with a copy of the classpath and allows
72   * for transformers to be added to the ClassLoader for load-time weaving.
73   *
74   * <p>Useful when writing tests that use JPA with EclipseLink since it depends upon load-time weaving.</p>
75   *
76   * <p>In order to use this class, you must have a {@link BootstrapTest} annotation available somewhere in the hierarchy
77   * of your test class (usually on the same class where the {@link RunWith} annotation is specified which references this
78   * runner class). This informs the runner about a test that it can run to execute any one-time initialization for
79   * the test suite. Ideally, this bootstrap test will execute code which loads JPA persistence units and any associated
80   * ClassFileTransformers for load-time weaving. This is necessary because it is common for an integration test to have
81   * references in the test class itself to JPA entities which need to be weaved. When this occurs, if the persistence
82   * units and ClassFileTransformers are not properly loaded before the entity classes are loaded by the classloader, then
83   * instrumentation will (silently!) fail to occur.</p>
84   *
85   * <p>Much of the code in this class was copied from the JUnit ParentRunner, BlockJUnit4ClassRunner, and
86   * TomcatInstrumentableClassLoader.</p>
87   *
88   * @author Kuali Rice Team (rice.collab@kuali.org)
89   */
90  public class LoadTimeWeavableTestRunner extends Runner implements Filterable, Sortable {
91  
92      private static final String[] JUNIT_CLASSLOADER_EXCLUDES = { "org.junit.", "junit.framework." };
93  
94      private final TestClass originalTestClass;
95      private TestClass fTestClass;
96      private Method currentMethod;
97  
98      // static because we only need one custom loader per JVM in which the tests are running, otherwise the memory
99      // 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 }