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