1
2
3
4
5
6 package mockit.integration.junit4;
7
8 import static mockit.internal.util.StackTrace.filterStackTrace;
9
10 import edu.umd.cs.findbugs.annotations.NonNull;
11 import edu.umd.cs.findbugs.annotations.Nullable;
12
13 import java.lang.reflect.Method;
14
15 import mockit.integration.TestRunnerDecorator;
16 import mockit.internal.expectations.RecordAndReplayExecution;
17 import mockit.internal.faking.FakeInvocation;
18 import mockit.internal.state.SavePoint;
19 import mockit.internal.state.TestRun;
20
21 import org.junit.After;
22 import org.junit.AfterClass;
23 import org.junit.Before;
24 import org.junit.BeforeClass;
25 import org.junit.Test;
26 import org.junit.runners.model.FrameworkMethod;
27
28 final class JUnit4TestRunnerDecorator extends TestRunnerDecorator {
29 @Nullable
30 Object invokeExplosively(@NonNull FakeInvocation invocation, @Nullable Object target, Object... params)
31 throws Throwable {
32 FrameworkMethod it = invocation.getInvokedInstance();
33 assert it != null;
34
35
36 if (target == null) {
37 try {
38 return executeClassMethod(invocation, params);
39 } catch (Throwable t) {
40 filterStackTrace(t);
41 throw t;
42 }
43 }
44
45 handleMockingOutsideTestMethods(target);
46
47
48 if (it.getAnnotation(Test.class) == null) {
49 if (shouldPrepareForNextTest && it.getAnnotation(Before.class) != null) {
50 prepareToExecuteSetupMethod(target);
51 }
52
53 TestRun.setRunningIndividualTest(target);
54
55 try {
56 invocation.prepareToProceedFromNonRecursiveMock();
57 return it.invokeExplosively(target, params);
58 } catch (Throwable t) {
59
60 RecordAndReplayExecution.endCurrentReplayIfAny();
61 filterStackTrace(t);
62 throw t;
63 } finally {
64 if (it.getAnnotation(After.class) != null) {
65 shouldPrepareForNextTest = true;
66 }
67 }
68 }
69
70 if (shouldPrepareForNextTest) {
71 prepareForNextTest();
72 }
73
74 shouldPrepareForNextTest = true;
75
76 try {
77 executeTestMethod(invocation, target, params);
78 return null;
79 } catch (Throwable t) {
80 filterStackTrace(t);
81 throw t;
82 } finally {
83 TestRun.finishCurrentTestExecution();
84 }
85 }
86
87 @Nullable
88 private static Object executeClassMethod(@NonNull FakeInvocation inv, @NonNull Object[] params) throws Throwable {
89 FrameworkMethod method = inv.getInvokedInstance();
90 assert method != null;
91 handleMockingOutsideTests(method);
92
93 TestRun.clearCurrentTestInstance();
94 inv.prepareToProceedFromNonRecursiveMock();
95
96 return method.invokeExplosively(null, params);
97 }
98
99 private void prepareToExecuteSetupMethod(@NonNull Object target) {
100 discardTestLevelMockedTypes();
101 prepareForNextTest();
102 shouldPrepareForNextTest = false;
103 createInstancesForTestedFieldsBeforeSetup(target);
104 }
105
106 private static void handleMockingOutsideTests(@NonNull FrameworkMethod it) {
107 Class<?> testClass = it.getMethod().getDeclaringClass();
108
109 TestRun.enterNoMockingZone();
110
111 try {
112 Class<?> currentTestClass = TestRun.getCurrentTestClass();
113
114 if (currentTestClass != null && testClass.isAssignableFrom(currentTestClass)
115 && it.getAnnotation(AfterClass.class) != null) {
116 cleanUpMocksFromPreviousTest();
117 }
118
119 if (it.getAnnotation(BeforeClass.class) != null) {
120 updateTestClassState(null, testClass);
121 }
122 } finally {
123 TestRun.exitNoMockingZone();
124 }
125 }
126
127 private static void handleMockingOutsideTestMethods(@NonNull Object target) {
128 Class<?> testClass = target.getClass();
129
130 TestRun.enterNoMockingZone();
131
132 try {
133 updateTestClassState(target, testClass);
134 } finally {
135 TestRun.exitNoMockingZone();
136 }
137 }
138
139 private static void executeTestMethod(@NonNull FakeInvocation invocation, @NonNull Object testInstance,
140 @Nullable Object... parameters) throws Throwable {
141 SavePoint savePoint = new SavePoint();
142
143 TestRun.setRunningIndividualTest(testInstance);
144
145 FrameworkMethod it = invocation.getInvokedInstance();
146 assert it != null;
147 Method testMethod = it.getMethod();
148 Throwable testFailure = null;
149 boolean testFailureExpected = false;
150
151 try {
152 createInstancesForTestedFieldsFromBaseClasses(testInstance);
153 Object[] annotatedParameters = createInstancesForAnnotatedParameters(testInstance, testMethod, parameters);
154 createInstancesForTestedFields(testInstance);
155
156 invocation.prepareToProceedFromNonRecursiveMock();
157
158 Object[] params = annotatedParameters == null ? parameters : annotatedParameters;
159 it.invokeExplosively(testInstance, params);
160 } catch (Throwable thrownByTest) {
161 testFailure = thrownByTest;
162 Class<?> expectedType = testMethod.getAnnotation(Test.class).expected();
163 testFailureExpected = expectedType.isAssignableFrom(thrownByTest.getClass());
164 } finally {
165 concludeTestMethodExecution(savePoint, testFailure, testFailureExpected);
166 }
167 }
168 }