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.assertSame;
10  
11  import edu.umd.cs.findbugs.annotations.NonNull;
12  
13  import java.io.Writer;
14  
15  import mockit.integration.junit5.JMockitExtension;
16  
17  import org.junit.jupiter.api.Test;
18  import org.junit.jupiter.api.extension.ExtendWith;
19  
20  /**
21   * The Class MockedClassWithSuperClassTest.
22   */
23  @ExtendWith(JMockitExtension.class)
24  class MockedClassWithSuperClassTest {
25  
26      /**
27       * The Class SubclassOfJREClass.
28       */
29      static class SubclassOfJREClass extends Writer {
30          @Override
31          public void write(@NonNull char[] cbuf, int off, int len) {
32          }
33  
34          @Override
35          public void flush() {
36          }
37  
38          @Override
39          public void close() {
40              throw new UnsupportedOperationException();
41          }
42      }
43  
44      /**
45       * The Class BaseClass.
46       */
47      static class BaseClass {
48  
49          /**
50           * Do something.
51           *
52           * @return the int
53           */
54          protected int doSomething() {
55              return 123;
56          }
57  
58          /**
59           * Static method.
60           *
61           * @return the int
62           */
63          static int staticMethod() {
64              return -1;
65          }
66      }
67  
68      /**
69       * The Class Subclass.
70       */
71      public static class Subclass extends BaseClass {
72          /**
73           * Gets the single instance of Subclass.
74           *
75           * @return single instance of Subclass
76           */
77          BaseClass getInstance() {
78              return this;
79          }
80      }
81  
82      /**
83       * Mocked class extending JRE class.
84       *
85       * @param mock
86       *            the mock
87       *
88       * @throws Exception
89       *             the exception
90       */
91      @Test
92      void mockedClassExtendingJREClass(@Mocked SubclassOfJREClass mock) throws Exception {
93          // Mocked:
94          assertSame(mock, mock.append("a"));
95          assertSame(mock, mock.append('a'));
96          mock.close();
97  
98          // Not mocked:
99          Writer w = new Writer() {
100             @Override
101             public void write(@NonNull char[] cbuf, int off, int len) {
102             }
103 
104             @Override
105             public void flush() {
106             }
107 
108             @Override
109             public void close() {
110             }
111         };
112         assertSame(w, w.append("Test1"));
113         assertSame(w, w.append('b'));
114 
115         try {
116             new SubclassOfJREClass() {
117             }.close();
118         } catch (UnsupportedOperationException ignore) {
119         }
120     }
121 
122     /**
123      * Mocked class extending non JRE class.
124      *
125      * @param mock
126      *            the mock
127      */
128     @Test
129     void mockedClassExtendingNonJREClass(@Mocked final Subclass mock) {
130         new Expectations() {
131             {
132                 mock.doSomething();
133                 result = 45;
134                 times = 2;
135             }
136         };
137 
138         // Mocked:
139         assertEquals(45, mock.doSomething());
140         assertEquals(45, new Subclass().doSomething());
141 
142         // Not mocked:
143         assertEquals(123, new Subclass() {
144         }.doSomething());
145 
146         BaseClass b1 = new BaseClass();
147         BaseClass b2 = new BaseClass() {
148             @Override
149             protected int doSomething() {
150                 return super.doSomething() - 23;
151             }
152         };
153         assertEquals(123, b1.doSomething());
154         assertEquals(100, b2.doSomething());
155     }
156 
157     /**
158      * Cascading subclass with method returning cascaded base class instance.
159      *
160      * @param mock
161      *            the mock
162      */
163     @Test
164     void cascadingSubclassWithMethodReturningCascadedBaseClassInstance(@Mocked Subclass mock) {
165         // The subclass is already mocked at this point, when the cascaded instance gets created.
166         BaseClass cascaded = mock.getInstance();
167 
168         assertEquals(0, cascaded.doSomething());
169         assertEquals(0, mock.doSomething());
170     }
171 
172     /**
173      * Record expectation on static method from base class.
174      *
175      * @param unused
176      *            the unused
177      */
178     @Test
179     void recordExpectationOnStaticMethodFromBaseClass(@Mocked Subclass unused) {
180         new Expectations() {
181             {
182                 BaseClass.staticMethod();
183                 result = 123;
184             }
185         };
186 
187         assertEquals(123, BaseClass.staticMethod());
188     }
189 
190     /**
191      * The Class BaseClassWithConstructor.
192      */
193     static class BaseClassWithConstructor {
194         /**
195          * Instantiates a new base class with constructor.
196          *
197          * @param b
198          *            the b
199          */
200         BaseClassWithConstructor(@SuppressWarnings("unused") boolean b) {
201         }
202     }
203 
204     /**
205      * The Class DerivedClass.
206      */
207     static class DerivedClass extends BaseClassWithConstructor {
208 
209         /**
210          * Instantiates a new derived class.
211          */
212         protected DerivedClass() {
213             // TRYCATCHBLOCK instruction appears before call to super, which caused a VerifyError.
214             super(true);
215             try {
216                 doSomething();
217             } catch (RuntimeException ignore) {
218             }
219         }
220 
221         /**
222          * Do something.
223          */
224         private void doSomething() {
225         }
226     }
227 
228     /**
229      * Mock subclass with constructor containing try catch.
230      *
231      * @param mock
232      *            the mock
233      */
234     @Test
235     void mockSubclassWithConstructorContainingTryCatch(@Mocked DerivedClass mock) {
236         new DerivedClass();
237     }
238 
239     /**
240      * The Class Subclass2.
241      */
242     static class Subclass2 extends BaseClass {
243     }
244 
245     /**
246      * Record same method on different mocked subclasses.
247      *
248      * @param mock1
249      *            the mock 1
250      * @param mock2
251      *            the mock 2
252      */
253     @Test
254     void recordSameMethodOnDifferentMockedSubclasses(@Mocked final Subclass mock1, @Mocked final Subclass2 mock2) {
255         new Expectations() {
256             {
257                 mock1.doSomething();
258                 result = 1;
259                 mock2.doSomething();
260                 result = 2;
261             }
262         };
263 
264         assertEquals(1, mock1.doSomething());
265         assertEquals(2, mock2.doSomething());
266     }
267 
268     /**
269      * Record method on mocked base class but replay on subclass instance.
270      *
271      * @param baseMock
272      *            the base mock
273      */
274     @Test
275     void recordMethodOnMockedBaseClassButReplayOnSubclassInstance(@Mocked final BaseClass baseMock) {
276         new Expectations() {
277             {
278                 baseMock.doSomething();
279                 result = 45;
280             }
281         };
282 
283         Subclass derived = new Subclass();
284         assertEquals(123, derived.doSomething());
285         assertEquals(45, baseMock.doSomething());
286     }
287 
288     /**
289      * The Class BaseClassWithTwoConstructors.
290      */
291     static class BaseClassWithTwoConstructors {
292 
293         /** The value. */
294         final int value;
295 
296         /**
297          * Instantiates a new base class with two constructors.
298          */
299         @SuppressWarnings("unused")
300         BaseClassWithTwoConstructors() {
301             value = 1;
302         }
303 
304         /**
305          * Instantiates a new base class with two constructors.
306          *
307          * @param value
308          *            the value
309          */
310         BaseClassWithTwoConstructors(int value) {
311             this.value = value;
312         }
313     }
314 
315     /**
316      * The Class SubclassWithOneConstructor.
317      */
318     static class SubclassWithOneConstructor extends BaseClassWithTwoConstructors {
319         /**
320          * Instantiates a new subclass with one constructor.
321          */
322         SubclassWithOneConstructor() {
323             super(2);
324         }
325     }
326 
327     /**
328      * The Class SecondLevelSubclass1.
329      */
330     static final class SecondLevelSubclass1 extends SubclassWithOneConstructor {
331     }
332 
333     /**
334      * Mock direct subclass of base with two constructors but instantiate second level subclass.
335      *
336      * @param mock
337      *            the mock
338      */
339     @Test
340     void mockDirectSubclassOfBaseWithTwoConstructorsButInstantiateSecondLevelSubclass(
341             @Mocked SubclassWithOneConstructor mock) {
342         int value = new SecondLevelSubclass1().value;
343         assertEquals(2, value);
344     }
345 
346     /**
347      * The Class SecondLevelSubclass2.
348      */
349     static final class SecondLevelSubclass2 extends SubclassWithOneConstructor {
350     }
351 
352     /**
353      * Mock one subclass but instantiate unmocked sibling.
354      *
355      * @param mock
356      *            the mock
357      */
358     @Test
359     void mockOneSubclassButInstantiateUnmockedSibling(@Mocked SecondLevelSubclass1 mock) {
360         int value = new SecondLevelSubclass2().value;
361         assertEquals(2, value);
362     }
363 }