1 package mockit;
2
3 import static java.util.Arrays.asList;
4
5 import static org.junit.jupiter.api.Assertions.assertEquals;
6 import static org.junit.jupiter.api.Assertions.assertSame;
7 import static org.junit.jupiter.api.Assertions.fail;
8
9 import java.lang.reflect.Member;
10 import java.lang.reflect.Method;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
14
15 import org.junit.jupiter.api.Test;
16
17
18
19
20 final class FakingEverythingTest {
21
22
23 final List<String> traces = new ArrayList<>();
24
25
26
27
28
29
30
31 void traceEntry(Invocation inv) {
32 traces.add("Entered " + getDescription(inv));
33 }
34
35
36
37
38
39
40
41 void traceExit(Invocation inv) {
42 traces.add("Exited " + getDescription(inv));
43 }
44
45
46
47
48
49
50
51
52
53 String getDescription(Invocation inv) {
54 Member member = inv.getInvokedMember();
55 String args = Arrays.toString(inv.getInvokedArguments());
56 Object instance = inv.getInvokedInstance();
57 return member.getDeclaringClass().getSimpleName() + '#' + member.getName() + " with " + args + " on "
58 + instance;
59 }
60
61
62
63
64 @Test
65 void fakeEveryMethodInSingleClass() {
66 new MockUp<TargetClass>() {
67 @Mock
68 Object $advice(Invocation inv) {
69 traceEntry(inv);
70
71 try {
72 return inv.proceed();
73 } finally {
74 traceExit(inv);
75 }
76 }
77
78 @Mock
79 void validateSomething(Invocation inv) {
80 Method m = inv.getInvokedMember();
81 assertEquals("validateSomething", m.getName());
82 }
83 };
84
85 TargetClass.staticMethod(123);
86 final TargetClass tc0 = new TargetClass();
87 assertEquals(4, tc0.doSomething("test", true));
88 tc0.performAction(new Runnable() {
89 @Override
90 public void run() {
91 tc0.doSomething("internal", false);
92 }
93
94 @Override
95 public String toString() {
96 return "action";
97 }
98 });
99 TargetClass tc1 = new TargetClass(1);
100 tc1.performAction(null);
101 tc1.validateSomething();
102
103 List<String> expectedTraces = asList("Entered TargetClass#staticMethod with [123] on null",
104 "Exited TargetClass#staticMethod with [123] on null",
105 "Entered TargetClass#doSomething with [test, true] on TargetClass0",
106 "Exited TargetClass#doSomething with [test, true] on TargetClass0",
107 "Entered TargetClass#performAction with [action] on TargetClass0",
108 "Entered TargetClass#doSomething with [internal, false] on TargetClass0",
109 "Exited TargetClass#doSomething with [internal, false] on TargetClass0",
110 "Exited TargetClass#performAction with [action] on TargetClass0",
111 "Entered TargetClass#performAction with [null] on TargetClass1",
112 "Exited TargetClass#performAction with [null] on TargetClass1");
113 assertEquals(expectedTraces, traces);
114 }
115
116
117
118
119 @Test
120 void fakeEveryMethodInSingleClassWithAdviceOnly() {
121 new MockUp<TargetClass>() {
122 @Mock
123 Object $advice(Invocation inv) {
124 Integer i = inv.proceed();
125 return i + 2;
126 }
127 };
128
129 assertEquals(1, new TargetClass().doSomething("", false));
130 }
131
132
133
134
135
136
137
138 @Test
139 <B extends TargetClass> void fakeEveryMethodInClassHierarchy() {
140 new MockUp<B>() {
141 @Mock
142 Object $advice(Invocation inv) {
143 traceEntry(inv);
144
145 try {
146 return inv.proceed();
147 } finally {
148 traceExit(inv);
149 }
150 }
151 };
152
153 final TargetSubclass s1 = new TargetSubclass(1);
154 assertEquals(4, s1.doSomething("test", true));
155 assertEquals("123", s1.additionalMethod(123));
156 s1.performAction(new Runnable() {
157 @Override
158 public void run() {
159 assertSame(s1, this);
160 }
161
162 @Override
163 public String toString() {
164 return "sub-action";
165 }
166 });
167
168 TargetClass s2 = new TargetClass(2);
169 s2.performAction(null);
170
171 try {
172 s2.validateSomething();
173 fail();
174 } catch (IllegalArgumentException e) {
175 assertEquals("Invalid something", e.getMessage());
176 }
177
178 List<String> expectedTraces = asList("Entered TargetClass#doSomething with [test, true] on TargetSubclass1",
179 "Exited TargetClass#doSomething with [test, true] on TargetSubclass1",
180 "Entered TargetSubclass#additionalMethod with [123] on TargetSubclass1",
181 "Exited TargetSubclass#additionalMethod with [123] on TargetSubclass1",
182 "Entered TargetSubclass#performAction with [sub-action] on TargetSubclass1",
183 "Entered TargetSubclass#additionalMethod with [45] on TargetSubclass1",
184 "Exited TargetSubclass#additionalMethod with [45] on TargetSubclass1",
185 "Exited TargetSubclass#performAction with [sub-action] on TargetSubclass1",
186 "Entered TargetClass#performAction with [null] on TargetClass2",
187 "Exited TargetClass#performAction with [null] on TargetClass2",
188 "Entered TargetClass#validateSomething with [] on TargetClass2",
189 "Exited TargetClass#validateSomething with [] on TargetClass2");
190 assertEquals(expectedTraces, traces);
191 }
192
193
194
195
196 public static final class PublicFake extends MockUp<TargetClass> {
197
198
199
200
201
202
203
204
205
206 @Mock
207 public static Object $advice(Invocation inv) {
208 Object[] args = inv.getInvokedArguments();
209
210 if (args.length > 0) {
211 Integer i = (Integer) args[0];
212 return -i;
213 }
214
215 return null;
216 }
217 }
218
219
220
221
222 @Test
223 void publicAdviceMethodInPublicFakeClass() {
224 new PublicFake();
225
226 new TargetClass().validateSomething();
227 int i = TargetClass.staticMethod(123);
228
229 assertEquals(-123, i);
230 }
231 }
232
233 class TargetClass {
234 final int value;
235
236 TargetClass() {
237 value = 0;
238 }
239
240 TargetClass(int value) {
241 this.value = value;
242 }
243
244 public static int staticMethod(int i) {
245 return i;
246 }
247
248 int doSomething(String s, boolean b) {
249 return b ? s.length() : -1;
250 }
251
252 protected void performAction(Runnable action) {
253 if (action != null) {
254 action.run();
255 }
256 }
257
258 protected void validateSomething() {
259 throw new IllegalArgumentException("Invalid something");
260 }
261
262 @Override
263 public String toString() {
264 return getClass().getSimpleName() + value;
265 }
266 }
267
268 final class TargetSubclass extends TargetClass {
269 TargetSubclass(int value) {
270 super(value);
271 }
272
273 String additionalMethod(int i) {
274 return String.valueOf(i);
275 }
276
277 @Override
278 protected void performAction(Runnable action) {
279 additionalMethod(45);
280 super.performAction(action);
281 }
282 }