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