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.assertThrows;
10  import static org.junit.jupiter.api.Assertions.assertTrue;
11  
12  import mockit.integration.junit5.JMockitExtension;
13  import mockit.internal.expectations.invocation.MissingInvocation;
14  import mockit.internal.expectations.invocation.UnexpectedInvocation;
15  
16  import org.junit.jupiter.api.Assertions;
17  import org.junit.jupiter.api.Test;
18  import org.junit.jupiter.api.extension.ExtendWith;
19  
20  /**
21   * The Class VerificationsTest.
22   */
23  @ExtendWith(JMockitExtension.class)
24  class VerificationsTest {
25  
26      /**
27       * The Class Dependency.
28       */
29      private static class Dependency {
30  
31          /**
32           * Sets the something.
33           *
34           * @param value
35           *            the new something
36           */
37          public void setSomething(@SuppressWarnings("unused") int value) {
38          }
39  
40          /**
41           * Sets the something else.
42           *
43           * @param value
44           *            the new something else
45           */
46          public void setSomethingElse(@SuppressWarnings("unused") String value) {
47          }
48  
49          /**
50           * Edits the A bunch more stuff.
51           */
52          public void editABunchMoreStuff() {
53          }
54  
55          /**
56           * Notify before save.
57           */
58          public void notifyBeforeSave() {
59          }
60  
61          /**
62           * Prepare.
63           */
64          public void prepare() {
65          }
66  
67          /**
68           * Save.
69           */
70          public void save() {
71          }
72      }
73  
74      /** The mock. */
75      @Mocked
76      Dependency mock;
77  
78      /**
79       * Exercise code under test.
80       */
81      void exerciseCodeUnderTest() {
82          mock.prepare();
83          mock.setSomething(123);
84          mock.setSomethingElse("anotherValue");
85          mock.setSomething(45);
86          mock.editABunchMoreStuff();
87          mock.notifyBeforeSave();
88          mock.save();
89      }
90  
91      /**
92       * Verify simple invocations.
93       */
94      @Test
95      void verifySimpleInvocations() {
96          exerciseCodeUnderTest();
97  
98          new Verifications() {
99              {
100                 mock.prepare();
101                 times = 1;
102                 mock.editABunchMoreStuff();
103                 mock.setSomething(45);
104             }
105         };
106     }
107 
108     /**
109      * Verify unrecorded invocation that never happens.
110      */
111     @Test
112     void verifyUnrecordedInvocationThatNeverHappens() {
113         Throwable exception = assertThrows(MissingInvocation.class, () -> {
114             mock.setSomething(123);
115             mock.prepare();
116 
117             new Verifications() {
118                 {
119                     mock.setSomething(45);
120                 }
121             };
122         });
123         assertTrue(exception.getMessage().contains("45"));
124     }
125 
126     /**
127      * Verify recorded invocation that never happens.
128      */
129     @Test
130     void verifyRecordedInvocationThatNeverHappens() {
131         new Expectations() {
132             {
133                 mock.editABunchMoreStuff();
134                 // Prevent failure here, let the verification fail instead:
135                 minTimes = 0;
136             }
137         };
138 
139         mock.setSomething(123);
140         mock.prepare();
141 
142         MissingInvocation e = assertThrows(MissingInvocation.class, () -> {
143             new Verifications() {
144                 {
145                     mock.editABunchMoreStuff();
146                 }
147             };
148         });
149     }
150 
151     /**
152      * Verify invocation that is allowed to happen once or more and happens once.
153      */
154     @Test
155     void verifyInvocationThatIsAllowedToHappenOnceOrMoreAndHappensOnce() {
156         mock.prepare();
157         mock.setSomething(123);
158         mock.save();
159 
160         new Verifications() {
161             {
162                 mock.setSomething(anyInt);
163                 mock.save();
164             }
165         };
166     }
167 
168     /**
169      * Verify unrecorded invocation that should happen but does not.
170      */
171     @Test
172     void verifyUnrecordedInvocationThatShouldHappenButDoesNot() {
173         assertThrows(MissingInvocation.class, () -> {
174             mock.setSomething(1);
175 
176             new Verifications() {
177                 {
178                     mock.notifyBeforeSave();
179                 }
180             };
181         });
182     }
183 
184     /**
185      * Verify invocations with invocation count.
186      */
187     @Test
188     void verifyInvocationsWithInvocationCount() {
189         mock.setSomething(3);
190         mock.save();
191         mock.setSomethingElse("test");
192         mock.save();
193 
194         new Verifications() {
195             {
196                 mock.save();
197                 times = 2;
198             }
199         };
200     }
201 
202     /**
203      * Verify invocations with invocation count larger than occurred.
204      */
205     @Test
206     void verifyInvocationsWithInvocationCountLargerThanOccurred() {
207         Throwable exception = assertThrows(MissingInvocation.class, () -> {
208             mock.setSomethingElse("test");
209             mock.setSomething(3);
210             mock.save();
211 
212             new Verifications() {
213                 {
214                     mock.setSomething(anyInt);
215                     times = 3;
216                 }
217             };
218         });
219         Assertions.assertTrue(exception.getMessage().contains("Missing 2 invocations"));
220         Assertions.assertTrue(exception.getMessage().contains("any int"));
221     }
222 
223     /**
224      * Verify invocations with invocation count smaller than occurred.
225      */
226     @Test
227     void verifyInvocationsWithInvocationCountSmallerThanOccurred() {
228         Throwable exception = assertThrows(UnexpectedInvocation.class, () -> {
229             mock.setSomethingElse("test");
230             mock.setSomething(3);
231             mock.save();
232             mock.setSomething(5);
233 
234             new Verifications() {
235                 {
236                     mock.setSomething(anyInt);
237                     times = 1;
238                 }
239             };
240         });
241         Assertions.assertTrue(exception.getMessage().contains("1 unexpected invocation"));
242         Assertions.assertTrue(exception.getMessage().contains("5"));
243     }
244 
245     /**
246      * Verify invocation that should not occur but did.
247      */
248     @Test
249     void verifyInvocationThatShouldNotOccurButDid() {
250         Throwable exception = assertThrows(UnexpectedInvocation.class, () -> {
251             mock.setSomething(5);
252             mock.setSomething(123);
253 
254             new Verifications() {
255                 {
256                     mock.setSomething(anyInt);
257                     maxTimes = 0;
258                 }
259             };
260         });
261         Assertions.assertTrue(exception.getMessage().contains("2 unexpected invocations"));
262         Assertions.assertTrue(exception.getMessage().contains("123"));
263     }
264 
265     /**
266      * Verify with argument matcher.
267      */
268     @Test
269     void verifyWithArgumentMatcher() {
270         exerciseCodeUnderTest();
271 
272         new Verifications() {
273             {
274                 mock.setSomething(anyInt);
275             }
276         };
277     }
278 
279     /**
280      * Verify with argument matcher and individual invocation counts.
281      */
282     @Test
283     void verifyWithArgumentMatcherAndIndividualInvocationCounts() {
284         exerciseCodeUnderTest();
285 
286         new Verifications() {
287             {
288                 mock.prepare();
289                 maxTimes = 1;
290                 mock.setSomething(anyInt);
291                 minTimes = 2;
292                 mock.editABunchMoreStuff();
293                 maxTimes = 5;
294                 mock.save();
295                 times = 1;
296             }
297         };
298     }
299 
300     /**
301      * Verify with custom argument matcher without argument value.
302      */
303     @Test
304     void verifyWithCustomArgumentMatcherWithoutArgumentValue() {
305         mock.setSomethingElse("not empty");
306 
307         new Verifications() {
308             {
309                 mock.setSomethingElse(with(new Delegate<String>() {
310                     @Mock
311                     boolean isNotEmpty(String s) {
312                         return !s.isEmpty();
313                     }
314                 }));
315             }
316         };
317     }
318 
319     /**
320      * Verify through captured arguments.
321      */
322     @Test
323     void verifyThroughCapturedArguments() {
324         Throwable exception = assertThrows(AssertionError.class, () -> {
325             mock.setSomethingElse("test");
326 
327             new Verifications() {
328                 {
329                     String value;
330                     mock.setSomethingElse(value = withCapture());
331                     // noinspection ConstantConditions
332                     assertEquals(0, value.length(), "not empty");
333                 }
334             };
335         });
336         Assertions.assertTrue(exception.getMessage().contains("not empty"));
337     }
338 
339     /**
340      * Verify with custom argument matcher.
341      */
342     @Test
343     void verifyWithCustomArgumentMatcher() {
344         Throwable exception = assertThrows(MissingInvocation.class, () -> {
345 
346             mock.setSomethingElse("test");
347 
348             new Verifications() {
349                 {
350                     mock.setSomethingElse(with(new Delegate<String>() {
351                         @Mock
352                         boolean isEmpty(String s) {
353                             return s.isEmpty();
354                         }
355                     }));
356                 }
357             };
358         });
359         Assertions.assertTrue(exception.getMessage().contains("isEmpty(\"test\")"));
360     }
361 
362     /**
363      * Verify invocation that matches expectation recorded with any matcher but with argument value which did not occur.
364      */
365     @Test
366     void verifyInvocationThatMatchesExpectationRecordedWithAnyMatcherButWithArgumentValueWhichDidNotOccur() {
367         Throwable exception = assertThrows(MissingInvocation.class, () -> {
368             new Expectations() {
369                 {
370                     mock.setSomething(anyInt);
371                 }
372             };
373 
374             mock.setSomething(123);
375 
376             new Verifications() {
377                 {
378                     mock.setSomething(45);
379                 }
380             };
381         });
382         Assertions.assertTrue(exception.getMessage().contains("45"));
383     }
384 
385     /**
386      * Verity two invocations to method matched on specific instance with no argument matchers.
387      *
388      * @param dep
389      *            the dep
390      */
391     @Test
392     void verityTwoInvocationsToMethodMatchedOnSpecificInstanceWithNoArgumentMatchers(@Injectable final Dependency dep) {
393         dep.editABunchMoreStuff();
394         dep.editABunchMoreStuff();
395 
396         new Verifications() {
397             {
398                 dep.editABunchMoreStuff();
399                 times = 2;
400             }
401         };
402     }
403 
404 }