View Javadoc
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   * The Class FakingEverythingTest.
19   */
20  final class FakingEverythingTest {
21  
22      /** The traces. */
23      final List<String> traces = new ArrayList<>();
24  
25      /**
26       * Trace entry.
27       *
28       * @param inv
29       *            the inv
30       */
31      void traceEntry(Invocation inv) {
32          traces.add("Entered " + getDescription(inv));
33      }
34  
35      /**
36       * Trace exit.
37       *
38       * @param inv
39       *            the inv
40       */
41      void traceExit(Invocation inv) {
42          traces.add("Exited " + getDescription(inv));
43      }
44  
45      /**
46       * Gets the description.
47       *
48       * @param inv
49       *            the inv
50       *
51       * @return the description
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       * Fake every method in single class.
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      * Fake every method in single class with advice only.
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      * Fake every method in class hierarchy.
134      *
135      * @param <B>
136      *            the generic type
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      * The Class PublicFake.
195      */
196     public static final class PublicFake extends MockUp<TargetClass> {
197 
198         /**
199          * $advice.
200          *
201          * @param inv
202          *            the inv
203          *
204          * @return the object
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      * Public advice method in public fake class.
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 }