1
2
3
4
5 package mockit.integration.testng;
6
7 import static mockit.internal.util.StackTrace.filterStackTrace;
8
9 import edu.umd.cs.findbugs.annotations.NonNull;
10 import edu.umd.cs.findbugs.annotations.Nullable;
11
12 import java.lang.reflect.Method;
13
14 import mockit.Expectations;
15 import mockit.coverage.testRedundancy.TestCoverage;
16 import mockit.integration.TestRunnerDecorator;
17 import mockit.internal.state.SavePoint;
18 import mockit.internal.state.TestRun;
19
20 import org.testng.IExecutionListener;
21 import org.testng.IInvokedMethod;
22 import org.testng.IInvokedMethodListener;
23 import org.testng.ITestNGMethod;
24 import org.testng.ITestResult;
25 import org.testng.TestException;
26 import org.testng.annotations.Test;
27
28
29
30
31
32
33
34 public final class TestNGRunnerDecorator extends TestRunnerDecorator
35 implements IInvokedMethodListener, IExecutionListener {
36 @NonNull
37 private final ThreadLocal<SavePoint> savePoint = new ThreadLocal<>();
38
39 @Override
40 public void beforeInvocation(@NonNull IInvokedMethod invokedMethod, @NonNull ITestResult testResult) {
41 ITestNGMethod testNGMethod = testResult.getMethod();
42 Class<?> testClass = testResult.getTestClass().getRealClass();
43
44 TestRun.clearNoMockingZone();
45
46 if (!invokedMethod.isTestMethod()) {
47 beforeConfigurationMethod(testNGMethod, testClass);
48 return;
49 }
50
51 Method method = testNGMethod.getConstructorOrMethod().getMethod();
52 exportCurrentTestMethodIfApplicable(method);
53
54 Object testInstance = testResult.getInstance();
55
56 if (testInstance == null || testInstance.getClass() != testClass) {
57
58
59
60 return;
61 }
62
63 TestRun.enterNoMockingZone();
64
65 try {
66 updateTestClassState(testInstance, testClass);
67 TestRun.setRunningIndividualTest(testInstance);
68
69 SavePoint testMethodSavePoint = new SavePoint();
70 savePoint.set(testMethodSavePoint);
71
72 if (shouldPrepareForNextTest) {
73 TestRun.prepareForNextTest();
74 shouldPrepareForNextTest = false;
75 clearTestedObjectsCreatedDuringSetup();
76 }
77
78 createInstancesForTestedFieldsFromBaseClasses(testInstance);
79 createInstancesForTestedFields(testInstance);
80 } finally {
81 TestRun.exitNoMockingZone();
82 }
83 }
84
85 private static void exportCurrentTestMethodIfApplicable(@Nullable Method testMethod) {
86 TestCoverage testCoverage = TestCoverage.INSTANCE;
87
88 if (testCoverage != null) {
89 testCoverage.setCurrentTestMethod(testMethod);
90 }
91 }
92
93 private void beforeConfigurationMethod(@NonNull ITestNGMethod method, @NonNull Class<?> testClass) {
94 TestRun.enterNoMockingZone();
95
96 try {
97 updateTestClassState(null, testClass);
98
99 if (method.isBeforeMethodConfiguration()) {
100 if (shouldPrepareForNextTest) {
101 discardTestLevelMockedTypes();
102 clearTestedObjectsCreatedDuringSetup();
103 }
104
105 Object testInstance = method.getInstance();
106 updateTestClassState(testInstance, testClass);
107
108 if (shouldPrepareForNextTest) {
109 prepareForNextTest();
110 shouldPrepareForNextTest = false;
111 createInstancesForTestedFieldsBeforeSetup(testInstance);
112 }
113
114 TestRun.setRunningIndividualTest(testInstance);
115 } else if (method.isAfterClassConfiguration()) {
116 TestRun.getExecutingTest().setRecordAndReplay(null);
117 cleanUpMocksFromPreviousTest();
118 TestRun.clearCurrentTestInstance();
119 } else if (!method.isAfterMethodConfiguration() && !method.isBeforeClassConfiguration()) {
120 TestRun.getExecutingTest().setRecordAndReplay(null);
121 cleanUpMocksFromPreviousTestClass();
122 TestRun.clearCurrentTestInstance();
123 TestRun.setCurrentTestClass(null);
124 }
125 } finally {
126 TestRun.exitNoMockingZone();
127 }
128 }
129
130 @Override
131 public void afterInvocation(@NonNull IInvokedMethod invokedMethod, @NonNull ITestResult testResult) {
132 if (!invokedMethod.isTestMethod()) {
133 afterConfigurationMethod(testResult);
134 return;
135 }
136
137 exportCurrentTestMethodIfApplicable(null);
138
139 SavePoint testMethodSavePoint = savePoint.get();
140
141 if (testMethodSavePoint == null) {
142 return;
143 }
144
145 TestRun.enterNoMockingZone();
146 shouldPrepareForNextTest = true;
147 savePoint.remove();
148
149 Throwable thrownByTest = testResult.getThrowable();
150
151 try {
152 if (thrownByTest == null) {
153 concludeTestExecutionWithNothingThrown(testMethodSavePoint, testResult);
154 } else if (thrownByTest instanceof TestException) {
155 concludeTestExecutionWithExpectedExceptionNotThrown(invokedMethod, testMethodSavePoint, testResult);
156 } else if (testResult.isSuccess()) {
157 concludeTestExecutionWithExpectedExceptionThrown(testMethodSavePoint, testResult, thrownByTest);
158 } else {
159 concludeTestExecutionWithUnexpectedExceptionThrown(testMethodSavePoint, thrownByTest);
160 }
161 } finally {
162 TestRun.finishCurrentTestExecution();
163 TestRun.clearCurrentTestInstance();
164 }
165 }
166
167 private static void afterConfigurationMethod(@NonNull ITestResult testResult) {
168 TestRun.enterNoMockingZone();
169
170 try {
171 ITestNGMethod method = testResult.getMethod();
172
173 if (method.isAfterMethodConfiguration()) {
174 Throwable thrownAfterTest = testResult.getThrowable();
175
176 if (thrownAfterTest != null) {
177 filterStackTrace(thrownAfterTest);
178 }
179 }
180 } finally {
181 TestRun.exitNoMockingZone();
182 }
183 }
184
185 private static void concludeTestExecutionWithNothingThrown(@NonNull SavePoint testMethodSavePoint,
186 @NonNull ITestResult testResult) {
187 try {
188 concludeTestMethodExecution(testMethodSavePoint, null, false);
189 } catch (Throwable t) {
190 filterStackTrace(t);
191 testResult.setThrowable(t);
192 testResult.setStatus(ITestResult.FAILURE);
193 }
194 }
195
196 private static void concludeTestExecutionWithExpectedExceptionNotThrown(@NonNull IInvokedMethod invokedMethod,
197 @NonNull SavePoint testMethodSavePoint, @NonNull ITestResult testResult) {
198 try {
199 concludeTestMethodExecution(testMethodSavePoint, null, false);
200 } catch (Throwable t) {
201 filterStackTrace(t);
202
203 if (isExpectedException(invokedMethod, t)) {
204 testResult.setThrowable(null);
205 testResult.setStatus(ITestResult.SUCCESS);
206 } else {
207 filterStackTrace(testResult.getThrowable());
208 }
209 }
210 }
211
212 private static void concludeTestExecutionWithExpectedExceptionThrown(@NonNull SavePoint testMethodSavePoint,
213 @NonNull ITestResult testResult, @NonNull Throwable thrownByTest) {
214 filterStackTrace(thrownByTest);
215
216 try {
217 concludeTestMethodExecution(testMethodSavePoint, thrownByTest, true);
218 } catch (Throwable t) {
219 if (t != thrownByTest) {
220 filterStackTrace(t);
221 testResult.setThrowable(t);
222 testResult.setStatus(ITestResult.FAILURE);
223 }
224 }
225 }
226
227 private static void concludeTestExecutionWithUnexpectedExceptionThrown(@NonNull SavePoint testMethodSavePoint,
228 @NonNull Throwable thrownByTest) {
229 filterStackTrace(thrownByTest);
230
231 try {
232 concludeTestMethodExecution(testMethodSavePoint, thrownByTest, false);
233 } catch (Throwable ignored) {
234 }
235 }
236
237 private static boolean isExpectedException(@NonNull IInvokedMethod invokedMethod, @NonNull Throwable thrownByTest) {
238 Method testMethod = invokedMethod.getTestMethod().getConstructorOrMethod().getMethod();
239 Class<?>[] expectedExceptions = testMethod.getAnnotation(Test.class).expectedExceptions();
240 Class<? extends Throwable> thrownExceptionType = thrownByTest.getClass();
241
242 for (Class<?> expectedException : expectedExceptions) {
243 if (expectedException.isAssignableFrom(thrownExceptionType)) {
244 return true;
245 }
246 }
247
248 return false;
249 }
250
251 @Override
252 public void onExecutionStart() {
253 }
254
255 @Override
256 public void onExecutionFinish() {
257 TestRun.enterNoMockingZone();
258
259 try {
260 TestRunnerDecorator.cleanUpAllMocks();
261 } finally {
262
263 TestRun.clearNoMockingZone();
264 }
265 }
266 }