View Javadoc
1   package mockit;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertFalse;
5   import static org.junit.jupiter.api.Assertions.assertNotNull;
6   import static org.junit.jupiter.api.Assertions.assertNull;
7   import static org.junit.jupiter.api.Assertions.assertSame;
8   import static org.junit.jupiter.api.Assertions.assertThrows;
9   import static org.junit.jupiter.api.Assertions.assertTrue;
10  
11  import jakarta.faces.application.FacesMessage;
12  
13  import java.lang.reflect.Method;
14  
15  import javax.accessibility.AccessibleState;
16  
17  import mockit.MoreFakingTest.ClassWithNested.Nested;
18  
19  import org.junit.jupiter.api.Test;
20  
21  /**
22   * The Class MoreFakingTest.
23   */
24  @SuppressWarnings("JUnitTestMethodWithNoAssertions")
25  final class MoreFakingTest {
26  
27      /** The code under test. */
28      final CodeUnderTest codeUnderTest = new CodeUnderTest();
29  
30      /** The fake executed. */
31      boolean fakeExecuted;
32  
33      /**
34       * The Class CodeUnderTest.
35       */
36      static class CodeUnderTest {
37  
38          /** The dependency. */
39          private final Collaborator dependency = new Collaborator();
40  
41          /**
42           * Do something.
43           */
44          void doSomething() {
45              dependency.provideSomeService();
46          }
47  
48          /**
49           * Do something else.
50           *
51           * @param i
52           *            the i
53           *
54           * @return the long
55           */
56          long doSomethingElse(int i) {
57              return dependency.getThreadSpecificValue(i);
58          }
59      }
60  
61      /**
62       * The Class Collaborator.
63       */
64      public static class Collaborator {
65  
66          /** The xyz. */
67          static Object xyz;
68  
69          /** The value. */
70          protected int value;
71  
72          /**
73           * Instantiates a new collaborator.
74           */
75          public Collaborator() {
76          }
77  
78          /**
79           * Instantiates a new collaborator.
80           *
81           * @param value
82           *            the value
83           */
84          Collaborator(int value) {
85              this.value = value;
86          }
87  
88          /**
89           * Do internal.
90           *
91           * @return the string
92           */
93          @SuppressWarnings("DeprecatedIsStillUsed")
94          @Deprecated
95          protected static String doInternal() {
96              return "123";
97          }
98  
99          /**
100          * Provide some service.
101          */
102         public void provideSomeService() {
103             throw new RuntimeException("Real provideSomeService() called");
104         }
105 
106         /**
107          * Gets the value.
108          *
109          * @return the value
110          */
111         public int getValue() {
112             return value;
113         }
114 
115         /**
116          * Sets the value.
117          *
118          * @param value
119          *            the new value
120          */
121         void setValue(int value) {
122             this.value = value;
123         }
124 
125         /**
126          * Gets the thread specific value.
127          *
128          * @param i
129          *            the i
130          *
131          * @return the thread specific value
132          */
133         protected long getThreadSpecificValue(int i) {
134             return Thread.currentThread().getId() + i;
135         }
136     }
137 
138     /**
139      * The Class FakeCollaborator1.
140      */
141     static class FakeCollaborator1 extends MockUp<Collaborator> {
142 
143         /**
144          * Provide some service.
145          */
146         @Mock
147         void provideSomeService() {
148         }
149     }
150 
151     /**
152      * Fake doing nothing.
153      */
154     @Test
155     void fakeDoingNothing() {
156         new FakeCollaborator1();
157 
158         codeUnderTest.doSomething();
159     }
160 
161     /**
162      * Apply fakes from inner fake class with fake constructor.
163      */
164     @Test
165     void applyFakesFromInnerFakeClassWithFakeConstructor() {
166         new FakeCollaborator4();
167         assertFalse(fakeExecuted);
168 
169         new CodeUnderTest().doSomething();
170 
171         assertTrue(fakeExecuted);
172     }
173 
174     /**
175      * The Class FakeCollaborator4.
176      */
177     class FakeCollaborator4 extends MockUp<Collaborator> {
178 
179         /**
180          * $init.
181          */
182         @Mock
183         void $init() {
184             fakeExecuted = true;
185         }
186 
187         /**
188          * Provide some service.
189          */
190         @Mock
191         void provideSomeService() {
192         }
193     }
194 
195     /**
196      * Apply reentrant fake.
197      */
198     @Test
199     public void applyReentrantFake() {
200         new FakeCollaboratorWithReentrantFakeMethod();
201 
202         assertThrows(RuntimeException.class, () -> {
203             codeUnderTest.doSomething();
204         });
205     }
206 
207     /**
208      * The Class FakeCollaboratorWithReentrantFakeMethod.
209      */
210     static class FakeCollaboratorWithReentrantFakeMethod extends MockUp<Collaborator> {
211 
212         /**
213          * Gets the value.
214          *
215          * @return the value
216          */
217         @Mock
218         int getValue() {
219             return 123;
220         }
221 
222         /**
223          * Provide some service.
224          *
225          * @param inv
226          *            the inv
227          */
228         @Mock
229         void provideSomeService(Invocation inv) {
230             inv.proceed();
231         }
232     }
233 
234     /**
235      * Apply fake for constructor.
236      */
237     @Test
238     void applyFakeForConstructor() {
239         new FakeCollaboratorWithConstructorFake();
240 
241         new FacesMessage("test");
242     }
243 
244     /**
245      * The Class FakeCollaboratorWithConstructorFake.
246      */
247     static class FakeCollaboratorWithConstructorFake extends MockUp<FacesMessage> {
248 
249         /**
250          * $init.
251          *
252          * @param value
253          *            the value
254          */
255         @Mock
256         void $init(String value) {
257             assertEquals("test", value);
258         }
259     }
260 
261     /**
262      * The Class SubCollaborator.
263      */
264     public static class SubCollaborator extends Collaborator {
265 
266         /**
267          * Instantiates a new sub collaborator.
268          *
269          * @param i
270          *            the i
271          */
272         public SubCollaborator(int i) {
273             throw new RuntimeException(String.valueOf(i));
274         }
275 
276         @Override
277         public void provideSomeService() {
278             value = 123;
279         }
280     }
281 
282     /**
283      * Apply fake for class hierarchy.
284      */
285     @Test
286     void applyFakeForClassHierarchy() {
287         new MockUp<SubCollaborator>() {
288             @Mock
289             void $init(Invocation inv, int i) {
290                 assertNotNull(inv.getInvokedInstance());
291                 assertTrue(i > 0);
292             }
293 
294             @Mock
295             void provideSomeService(Invocation inv) {
296                 SubCollaborator it = inv.getInvokedInstance();
297                 it.value = 45;
298             }
299 
300             @Mock
301             int getValue(Invocation inv) {
302                 SubCollaborator it = inv.getInvokedInstance();
303                 assertNotNull(it);
304                 return 123;
305             }
306         };
307 
308         SubCollaborator collaborator = new SubCollaborator(123);
309         collaborator.provideSomeService();
310         assertEquals(45, collaborator.value);
311         assertEquals(123, collaborator.getValue());
312     }
313 
314     /**
315      * Apply fake for JRE class.
316      */
317     @Test
318     void applyFakeForJREClass() {
319         FakeThread fakeThread = new FakeThread();
320 
321         Thread.currentThread().interrupt();
322 
323         assertTrue(fakeThread.interrupted);
324     }
325 
326     /**
327      * The Class FakeThread.
328      */
329     public static class FakeThread extends MockUp<Thread> {
330 
331         /** The interrupted. */
332         boolean interrupted;
333 
334         /**
335          * Interrupt.
336          */
337         @Mock
338         public void interrupt() {
339             interrupted = true;
340         }
341     }
342 
343     /**
344      * Fake static initializer.
345      */
346     @Test
347     void fakeStaticInitializer() {
348         new MockUp<AccessibleState>() {
349             @Mock
350             void $clinit() {
351             }
352         };
353 
354         assertNull(AccessibleState.ACTIVE);
355     }
356 
357     /**
358      * The Class AnAbstractClass.
359      */
360     abstract static class AnAbstractClass {
361         /**
362          * Do something.
363          *
364          * @return the int
365          */
366         protected abstract int doSomething();
367     }
368 
369     /**
370      * Fake abstract class with fake for abstract method having invocation parameter.
371      *
372      * @param <A>
373      *            the generic type
374      */
375     @Test
376     <A extends AnAbstractClass> void fakeAbstractClassWithFakeForAbstractMethodHavingInvocationParameter() {
377         final AnAbstractClass obj = new AnAbstractClass() {
378             @Override
379             protected int doSomething() {
380                 return 0;
381             }
382         };
383 
384         new MockUp<A>() {
385             @Mock
386             int doSomething(Invocation inv) {
387                 assertSame(obj, inv.getInvokedInstance());
388                 Method invokedMethod = inv.getInvokedMember();
389                 assertTrue(AnAbstractClass.class.isAssignableFrom(invokedMethod.getDeclaringClass()));
390                 return 123;
391             }
392         };
393 
394         assertEquals(123, obj.doSomething());
395     }
396 
397     /**
398      * The Class GenericClass.
399      *
400      * @param <T>
401      *            the generic type
402      */
403     static class GenericClass<T> {
404         /**
405          * Do something.
406          *
407          * @return the t
408          */
409         protected T doSomething() {
410             return null;
411         }
412     }
413 
414     /**
415      * Fake generic class with fake having invocation parameter.
416      */
417     @Test
418     void fakeGenericClassWithFakeHavingInvocationParameter() {
419         new MockUp<GenericClass<String>>() {
420             @Mock
421             String doSomething(Invocation inv) {
422                 return "faked";
423             }
424         };
425 
426         GenericClass<String> faked = new GenericClass<>();
427         assertEquals("faked", faked.doSomething());
428     }
429 
430     /**
431      * Concurrent fake.
432      *
433      * @throws Exception
434      *             the exception
435      */
436     @Test
437     @SuppressWarnings("MethodWithMultipleLoops")
438     void concurrentFake() throws Exception {
439         new MockUp<Collaborator>() {
440             @Mock
441             long getThreadSpecificValue(int i) {
442                 return Thread.currentThread().getId() + 123;
443             }
444         };
445 
446         Thread[] threads = new Thread[5];
447 
448         for (int i = 0; i < threads.length; i++) {
449             threads[i] = new Thread() {
450                 @Override
451                 public void run() {
452                     long threadSpecificValue = Thread.currentThread().getId() + 123;
453                     long actualValue = new CodeUnderTest().doSomethingElse(0);
454                     assertEquals(threadSpecificValue, actualValue);
455                 }
456             };
457         }
458 
459         for (Thread thread : threads) {
460             thread.start();
461         }
462         for (Thread thread : threads) {
463             thread.join();
464         }
465     }
466 
467     /**
468      * Fake affects instances of specified subclass and not of base class.
469      */
470     @Test
471     void fakeAffectsInstancesOfSpecifiedSubclassAndNotOfBaseClass() {
472         new FakeForSubclass();
473 
474         // Faking applies to instance methods executed on instances of the subclass:
475         assertEquals(123, new SubCollaborator(5).getValue());
476 
477         // And to static methods from any class in the hierarchy:
478         // noinspection deprecation
479         assertEquals("faked", Collaborator.doInternal());
480 
481         // But not to instance methods executed on instances of the base class:
482         assertEquals(62, new Collaborator(62).getValue());
483     }
484 
485     /**
486      * The Class FakeForSubclass.
487      */
488     static class FakeForSubclass extends MockUp<SubCollaborator> {
489 
490         /**
491          * $init.
492          *
493          * @param i
494          *            the i
495          */
496         @Mock
497         void $init(int i) {
498         }
499 
500         /**
501          * Do internal.
502          *
503          * @return the string
504          */
505         @Mock
506         String doInternal() {
507             return "faked";
508         }
509 
510         /**
511          * Gets the value.
512          *
513          * @return the value
514          */
515         @Mock
516         int getValue() {
517             return 123;
518         }
519     }
520 
521     /**
522      * The Class ClassWithNested.
523      */
524     public static final class ClassWithNested {
525 
526         /**
527          * Do something.
528          */
529         public static void doSomething() {
530         }
531 
532         /**
533          * The Class Nested.
534          */
535         public static final class Nested {
536         }
537     }
538 
539     /**
540      * Fake A class having A nested class.
541      */
542     @Test
543     void fakeAClassHavingANestedClass() {
544         new MockUp<ClassWithNested>() {
545             @Mock
546             void doSomething() {
547             }
548         };
549 
550         Class<?> outerClass = Nested.class.getDeclaringClass();
551 
552         assertSame(ClassWithNested.class, outerClass);
553     }
554 }