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