View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit;
7   
8   import static org.junit.jupiter.api.Assertions.assertEquals;
9   import static org.junit.jupiter.api.Assertions.assertFalse;
10  import static org.junit.jupiter.api.Assertions.assertSame;
11  import static org.junit.jupiter.api.Assertions.assertThrows;
12  import static org.junit.jupiter.api.Assertions.assertTrue;
13  
14  import mockit.integration.junit5.JMockitExtension;
15  import mockit.internal.expectations.invocation.MissingInvocation;
16  
17  import org.junit.jupiter.api.Test;
18  import org.junit.jupiter.api.extension.ExtendWith;
19  
20  /**
21   * The Class DynamicOnInstanceMockingTest.
22   */
23  @ExtendWith(JMockitExtension.class)
24  class DynamicOnInstanceMockingTest {
25  
26      /**
27       * The Class Collaborator.
28       */
29      static class Collaborator {
30  
31          /** The value. */
32          protected int value;
33  
34          /**
35           * Instantiates a new collaborator.
36           */
37          Collaborator() {
38              value = -1;
39          }
40  
41          /**
42           * Instantiates a new collaborator.
43           *
44           * @param value
45           *            the value
46           */
47          Collaborator(int value) {
48              this.value = value;
49          }
50  
51          /**
52           * Gets the value.
53           *
54           * @return the value
55           */
56          int getValue() {
57              return value;
58          }
59  
60          /**
61           * Sets the value.
62           *
63           * @param value
64           *            the new value
65           */
66          void setValue(int value) {
67              this.value = value;
68          }
69      }
70  
71      /**
72       * The Class AnotherDependency.
73       */
74      static class AnotherDependency {
75  
76          /**
77           * Gets the name.
78           *
79           * @return the name
80           */
81          public String getName() {
82              return "";
83          }
84      }
85  
86      /**
87       * Mocking one instance and matching invocations only on that instance.
88       */
89      @Test
90      void mockingOneInstanceAndMatchingInvocationsOnlyOnThatInstance() {
91          Collaborator collaborator1 = new Collaborator();
92          Collaborator collaborator2 = new Collaborator();
93          final Collaborator collaborator3 = new Collaborator();
94  
95          new Expectations(collaborator3) {
96              {
97                  collaborator3.getValue();
98                  result = 3;
99              }
100         };
101 
102         assertEquals(-1, collaborator1.getValue());
103         assertEquals(-1, collaborator2.getValue());
104         assertEquals(3, collaborator3.getValue());
105         assertEquals(2, new Collaborator(2).getValue());
106     }
107 
108     /**
109      * Mocking two instances and matching invocations on each one.
110      */
111     @Test
112     void mockingTwoInstancesAndMatchingInvocationsOnEachOne() {
113         final Collaborator collaborator1 = new Collaborator();
114         Collaborator collaborator2 = new Collaborator();
115 
116         new Expectations(collaborator1, collaborator2) {
117             {
118                 collaborator1.getValue();
119                 result = 1;
120             }
121         };
122 
123         collaborator2.setValue(2);
124         assertEquals(2, collaborator2.getValue());
125         assertEquals(1, collaborator1.getValue());
126         assertEquals(3, new Collaborator(3).getValue());
127     }
128 
129     /**
130      * Mocking one instance but recording on another.
131      */
132     @Test
133     void mockingOneInstanceButRecordingOnAnother() {
134         Collaborator collaborator1 = new Collaborator();
135         final Collaborator collaborator2 = new Collaborator();
136         Collaborator collaborator3 = new Collaborator();
137 
138         new Expectations(collaborator1) {
139             {
140                 // A misuse of the API:
141                 collaborator2.getValue();
142                 result = -2;
143             }
144         };
145 
146         collaborator1.setValue(1);
147         collaborator2.setValue(2);
148         collaborator3.setValue(3);
149         assertEquals(1, collaborator1.getValue());
150         assertEquals(-2, collaborator2.getValue());
151         assertEquals(3, collaborator3.getValue());
152     }
153 
154     /**
155      * The Class Foo.
156      */
157     public static class Foo {
158 
159         /**
160          * Builds the value.
161          *
162          * @param s
163          *            the s
164          *
165          * @return the foo
166          */
167         Foo buildValue(@SuppressWarnings("unused") String s) {
168             return this;
169         }
170 
171         /**
172          * Do it.
173          *
174          * @return true, if successful
175          */
176         boolean doIt() {
177             return false;
178         }
179 
180         /**
181          * Do it again.
182          *
183          * @return true, if successful
184          */
185         boolean doItAgain() {
186             return false;
187         }
188 
189         /**
190          * Gets the bar.
191          *
192          * @return the bar
193          */
194         AnotherDependency getBar() {
195             return null;
196         }
197     }
198 
199     /**
200      * The Class SubFoo.
201      */
202     public static class SubFoo extends Foo {
203     }
204 
205     /**
206      * Record duplicate invocation on two dynamic mocks of different types but shared base class.
207      */
208     @Test
209     void recordDuplicateInvocationOnTwoDynamicMocksOfDifferentTypesButSharedBaseClass() {
210         final Foo f1 = new Foo();
211         final SubFoo f2 = new SubFoo();
212 
213         new Expectations(f1, f2) {
214             {
215                 f1.doIt();
216                 result = true;
217                 f2.doIt();
218                 result = false;
219             }
220         };
221 
222         assertTrue(f1.doIt());
223         assertFalse(f2.doIt());
224         assertFalse(new Foo().doIt());
225         assertFalse(new SubFoo().doIt());
226     }
227 
228     /**
229      * Verify method invocation count on mocked and non mocked instances.
230      */
231     @Test
232     void verifyMethodInvocationCountOnMockedAndNonMockedInstances() {
233         final Foo foo1 = new Foo();
234         final Foo foo2 = new Foo();
235 
236         new Expectations(foo1, foo2) {
237             {
238                 foo1.doIt();
239                 result = true;
240             }
241         };
242 
243         assertTrue(foo1.doIt());
244         assertFalse(foo2.doItAgain());
245         assertFalse(foo2.doIt());
246         final Foo foo3 = new Foo();
247         assertFalse(foo1.doItAgain());
248         assertFalse(foo3.doItAgain());
249         assertFalse(foo3.doIt());
250         assertFalse(foo3.doItAgain());
251 
252         new Verifications() {
253             {
254                 assertFalse(foo2.doIt());
255                 times = 1;
256                 assertFalse(foo1.doItAgain());
257                 times = 1;
258                 assertFalse(foo3.doItAgain());
259                 times = 2;
260             }
261         };
262     }
263 
264     /**
265      * Creates the cascaded mock from partially mocked instance.
266      */
267     @Test
268     void createCascadedMockFromPartiallyMockedInstance() {
269         final Foo foo = new Foo();
270 
271         new Expectations(foo) {
272             {
273                 foo.getBar().getName();
274                 result = "cascade";
275             }
276         };
277 
278         assertEquals("cascade", foo.getBar().getName());
279     }
280 
281     /**
282      * Use available mocked instance as cascade from partially mocked instance.
283      *
284      * @param bar
285      *            the bar
286      */
287     @Test
288     void useAvailableMockedInstanceAsCascadeFromPartiallyMockedInstance(@Mocked AnotherDependency bar) {
289         final Foo foo = new Foo();
290 
291         new Expectations(foo) {
292             {
293                 foo.getBar().getName();
294                 result = "cascade";
295             }
296         };
297 
298         AnotherDependency cascadedBar = foo.getBar();
299         assertSame(bar, cascadedBar);
300         assertEquals("cascade", cascadedBar.getName());
301     }
302 
303     /**
304      * The Class Bar.
305      */
306     static final class Bar extends AnotherDependency {
307     }
308 
309     /**
310      * Use available mocked subclass instance as cascade from partially mocked instance.
311      *
312      * @param bar
313      *            the bar
314      */
315     @Test
316     void useAvailableMockedSubclassInstanceAsCascadeFromPartiallyMockedInstance(@Mocked Bar bar) {
317         final Foo foo = new Foo();
318 
319         new Expectations(foo) {
320             {
321                 foo.getBar().getName();
322                 result = "cascade";
323             }
324         };
325 
326         AnotherDependency cascadedBar = foo.getBar();
327         assertSame(bar, cascadedBar);
328         assertEquals("cascade", cascadedBar.getName());
329     }
330 
331     /**
332      * Use itself as cascade from partially mocked instance.
333      */
334     @Test
335     void useItselfAsCascadeFromPartiallyMockedInstance() {
336         final Foo foo = new Foo();
337 
338         new Expectations(foo) {
339             {
340                 foo.buildValue(anyString).doIt();
341                 result = true;
342             }
343         };
344 
345         Foo cascadedFoo = foo.buildValue("test");
346         assertSame(foo, cascadedFoo);
347         assertTrue(cascadedFoo.doIt());
348     }
349 
350     /**
351      * Verify single invocation to mocked instance with additional invocation to same method on another instance.
352      */
353     @Test
354     void verifySingleInvocationToMockedInstanceWithAdditionalInvocationToSameMethodOnAnotherInstance() {
355         final Collaborator mocked = new Collaborator();
356 
357         new Expectations(mocked) {
358         };
359 
360         Collaborator notMocked = new Collaborator();
361         assertEquals(-1, notMocked.getValue());
362         assertEquals(-1, mocked.getValue());
363 
364         new Verifications() {
365             {
366                 mocked.getValue();
367                 times = 1;
368             }
369         };
370     }
371 
372     /**
373      * Verify ordered invocations to dynamically mocked instance with another instance involved but missing an
374      * invocation.
375      */
376     @Test
377     void verifyOrderedInvocationsToDynamicallyMockedInstanceWithAnotherInstanceInvolvedButMissingAnInvocation() {
378         assertThrows(MissingInvocation.class, () -> {
379             final Collaborator mock = new Collaborator();
380 
381             new Expectations(mock) {
382             };
383 
384             mock.setValue(1);
385             new Collaborator().setValue(2);
386 
387             new VerificationsInOrder() {
388                 {
389                     mock.setValue(1);
390                     times = 1;
391                     mock.setValue(2);
392                     times = 1; // must be missing
393                 }
394             };
395         });
396     }
397 
398     /**
399      * Verify ordered invocations to dynamically mocked instance with another instance involved.
400      */
401     @Test
402     void verifyOrderedInvocationsToDynamicallyMockedInstanceWithAnotherInstanceInvolved() {
403         final Collaborator mock = new Collaborator();
404 
405         new Expectations(mock) {
406             {
407                 mock.setValue(anyInt);
408             }
409         };
410 
411         mock.setValue(1);
412         new Collaborator().setValue(2);
413 
414         new VerificationsInOrder() {
415             {
416                 mock.setValue(1);
417                 times = 1;
418                 mock.setValue(2);
419                 times = 0;
420             }
421         };
422     }
423 }