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.assertNotSame;
10  import static org.junit.jupiter.api.Assertions.assertSame;
11  import static org.junit.jupiter.api.Assertions.fail;
12  
13  import mockit.integration.junit5.ExpectedException;
14  import mockit.integration.junit5.JMockitExtension;
15  import mockit.internal.expectations.invocation.MissingInvocation;
16  
17  import org.junit.jupiter.api.Assertions;
18  import org.junit.jupiter.api.Test;
19  import org.junit.jupiter.api.extension.ExtendWith;
20  
21  /**
22   * The Class MisusedMockingAPITest.
23   */
24  @ExtendWith(JMockitExtension.class)
25  class MisusedMockingAPITest {
26  
27      /**
28       * The Class Blah.
29       */
30      static class Blah {
31  
32          /** The name. */
33          @SuppressWarnings("RedundantStringConstructorCall")
34          final String name = "Blah";
35  
36          /**
37           * Value.
38           *
39           * @return the int
40           */
41          int value() {
42              return -1;
43          }
44  
45          /**
46           * Sets the value.
47           *
48           * @param value
49           *            the new value
50           */
51          void setValue(@SuppressWarnings("unused") int value) {
52          }
53  
54          /**
55           * Do something.
56           *
57           * @param b
58           *            the b
59           *
60           * @return the string
61           */
62          String doSomething(@SuppressWarnings("unused") boolean b) {
63              return "";
64          }
65  
66          /**
67           * Gets the something else.
68           *
69           * @return the something else
70           */
71          Runnable getSomethingElse() {
72              return null;
73          }
74      }
75  
76      /** The mock. */
77      @Mocked
78      Blah mock;
79  
80      // Arrange-Act-Assert non-conformance
81      // //////////////////////////////////////////////////////////////////////////////////////////////////
82  
83      /**
84       * Record expectation after invoking same method in replay phase.
85       */
86      @Test
87      void recordExpectationAfterInvokingSameMethodInReplayPhase() {
88          Assertions.assertEquals(0, mock.value());
89  
90          new Expectations() {
91              {
92                  mock.value();
93                  result = 1;
94              }
95          };
96  
97          Assertions.assertEquals(1, mock.value());
98      }
99  
100     // Duplicate/pointless recordings
101     // //////////////////////////////////////////////////////////////////////////////////////////////////////
102 
103     /**
104      * Record duplicate invocation with no arguments.
105      */
106     @Test
107     void recordDuplicateInvocationWithNoArguments() {
108         new Expectations() {
109             {
110                 mock.value();
111                 result = 1;
112                 mock.value();
113                 result = 2; // second recording overrides the first
114             }
115         };
116 
117         Assertions.assertEquals(2, mock.value());
118         Assertions.assertEquals(2, mock.value());
119     }
120 
121     /**
122      * Record duplicate invocation with argument matcher.
123      */
124     @Test
125     void recordDuplicateInvocationWithArgumentMatcher() {
126         new Expectations() {
127             {
128                 mock.setValue(anyInt);
129                 result = new UnknownError();
130                 mock.setValue(anyInt); // overrides the previous one
131             }
132         };
133 
134         mock.setValue(3);
135     }
136 
137     /**
138      * Record duplicate invocation in separate expectation blocks.
139      */
140     @Test
141     void recordDuplicateInvocationInSeparateExpectationBlocks() {
142         new Expectations() {
143             {
144                 mock.value();
145                 result = 1;
146             }
147         };
148         new Expectations() {
149             {
150                 mock.value();
151                 result = 2;
152             }
153         }; // overrides the previous expectation
154 
155         Assertions.assertEquals(2, mock.value());
156     }
157 
158     /**
159      * Record mock instance for constructor expectation.
160      */
161     @Test
162     @ExpectedException(MissingInvocation.class)
163     void recordMockInstanceForConstructorExpectation() {
164         Throwable exception = Assertions.assertThrows(IllegalArgumentException.class, () -> {
165             new Expectations() {
166                 {
167                     new Blah();
168                     result = mock; // invalid
169                 }
170             };
171 
172             new Blah();
173         });
174 
175         Assertions.assertTrue(exception.getMessage().contains("Invalid assignment"));
176         Assertions.assertTrue(exception.getMessage().contains("result"));
177         Assertions.assertTrue(exception.getMessage().contains("constructor"));
178     }
179 
180     // Order-related recordings
181     // ////////////////////////////////////////////////////////////////////////////////////////////////////////////
182 
183     /**
184      * Record unordered instantiation of class mocked twice.
185      *
186      * @param mock2
187      *            the mock 2
188      */
189     @Test
190     void recordUnorderedInstantiationOfClassMockedTwice(@Mocked final Blah mock2) {
191         new Expectations() {
192             {
193                 new Blah();
194                 times = 1;
195                 mock.value();
196                 result = 123;
197                 mock2.value();
198                 result = 45;
199             }
200         };
201 
202         Assertions.assertEquals(45, mock2.value());
203         Assertions.assertEquals(123, mock.value());
204         new Blah();
205     }
206 
207     /**
208      * Verify ordered instantiation of class mocked twice.
209      *
210      * @param mock2
211      *            the mock 2
212      */
213     @Test
214     void verifyOrderedInstantiationOfClassMockedTwice(@Mocked final Blah mock2) {
215         new Blah();
216         mock2.doSomething(true);
217 
218         new VerificationsInOrder() {
219             {
220                 new Blah();
221                 mock2.doSomething(anyBoolean);
222             }
223         };
224     }
225 
226     /**
227      * Verify unordered instantiation of class mocked twice.
228      *
229      * @param mock2
230      *            the mock 2
231      */
232     @Test
233     void verifyUnorderedInstantiationOfClassMockedTwice(@Mocked final Blah mock2) {
234         mock.doSomething(false);
235         mock2.doSomething(true);
236         new Blah();
237 
238         new Verifications() {
239             {
240                 mock2.doSomething(true);
241                 new Blah();
242                 mock.doSomething(false);
243             }
244         };
245     }
246 
247     // Cascading
248     // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
249 
250     /**
251      * Ambiguous cascading when multiple valid candidates are available.
252      *
253      * @param r1
254      *            the r 1
255      * @param r2
256      *            the r 2
257      */
258     @Test
259     void ambiguousCascadingWhenMultipleValidCandidatesAreAvailable(@Injectable Runnable r1, @Injectable Runnable r2) {
260         Runnable cascaded = mock.getSomethingElse(); // which one to return: r1 or r2?
261 
262         Assertions.assertSame(r2, cascaded); // currently, last mock to be declared wins
263     }
264 
265     // @Tested/@Injectable usage
266     // ///////////////////////////////////////////////////////////////////////////////////////////////////////////
267 
268     /**
269      * The Class TestedClass.
270      */
271     static class TestedClass {
272         /** The action. */
273         Runnable action;
274     }
275 
276     /** The mock action. */
277     @Injectable
278     static Runnable mockAction = new Runnable() {
279         @Override
280         public void run() {
281         }
282     };
283 
284     /** The tested. */
285     @Tested
286     TestedClass tested;
287 
288     /**
289      * Check static injectable is not used.
290      */
291     @Test
292     void checkStaticInjectableIsNotUsed() {
293         Assertions.assertNotSame(mockAction, tested.action);
294     }
295 
296     // Other cases
297     // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
298 
299     /**
300      * The Class CustomException.
301      */
302     static final class CustomException extends Exception {
303 
304         private static final long serialVersionUID = 1L;
305     }
306 
307     /**
308      * Attempting to mock all instances of exception subclass.
309      *
310      * @param anyCustomException
311      *            the any custom exception
312      */
313     @Test
314     @ExpectedException(IllegalArgumentException.class)
315     void attemptingToMockAllInstancesOfExceptionSubclass(@Mocked CustomException anyCustomException) {
316         fail("Shouldn't get here");
317     }
318 }