1
2
3
4
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.assertNull;
11 import static org.junit.jupiter.api.Assertions.assertTrue;
12 import static org.junit.jupiter.api.Assertions.fail;
13
14 import jakarta.xml.bind.annotation.XmlElement;
15
16 import java.lang.reflect.Constructor;
17 import java.util.Date;
18 import java.util.List;
19
20 import mockit.integration.junit5.ExpectedException;
21 import mockit.integration.junit5.JMockitExtension;
22 import mockit.internal.expectations.invocation.MissingInvocation;
23 import mockit.internal.expectations.invocation.UnexpectedInvocation;
24
25 import org.junit.jupiter.api.Assertions;
26 import org.junit.jupiter.api.Disabled;
27 import org.junit.jupiter.api.Test;
28 import org.junit.jupiter.api.extension.ExtendWith;
29
30
31
32
33 @ExtendWith(JMockitExtension.class)
34 @SuppressWarnings("deprecation")
35 class PartialMockingTest {
36
37
38
39
40 @Deprecated
41 static class Collaborator {
42
43
44 @Deprecated
45 protected int value;
46
47
48
49
50 Collaborator() {
51 value = -1;
52 }
53
54
55
56
57
58
59
60 @Deprecated
61 Collaborator(@Deprecated int value) {
62 this.value = value;
63 }
64
65
66
67
68
69
70 final int getValue() {
71 return value;
72 }
73
74
75
76
77
78
79
80 void setValue(int value) {
81 this.value = value;
82 }
83
84
85
86
87
88
89
90
91
92
93
94
95
96 @SuppressWarnings("unused")
97 final boolean simpleOperation(int a, @XmlElement(name = "test") String b, Date c) {
98 return true;
99 }
100
101
102
103
104
105
106
107
108
109 static void doSomething(@SuppressWarnings("unused") boolean b, @SuppressWarnings("unused") String s) {
110 throw new IllegalStateException();
111 }
112
113
114
115
116
117
118 @Disabled("test")
119 boolean methodWhichCallsAnotherInTheSameClass() {
120 return simpleOperation(1, "internal", null);
121 }
122
123
124
125
126
127
128 String overridableMethod() {
129 return "base";
130 }
131 }
132
133
134
135
136 @Test
137 @ExpectedException(value = IllegalArgumentException.class, expectedMessages = { "Invalid Class", "partial mocking",
138 "Collaborator" })
139 void attemptToPartiallyMockAClass() {
140 new Expectations(Collaborator.class) {
141 };
142 }
143
144
145
146
147 @Test
148 void dynamicMockFullyVerified_verifyAllRecordedExpectationsButNotAllOfTheReplayedOnes() {
149 final Collaborator collaborator = new Collaborator(0);
150
151 new Expectations(collaborator) {
152 {
153 collaborator.setValue(1);
154 }
155 };
156
157 collaborator.setValue(1);
158 collaborator.setValue(2);
159
160
161 new FullVerifications() {
162
163
164 };
165 }
166
167
168
169
170 @Test
171 void dynamicMockFullyVerifiedInOrder_verifyAllRecordedExpectationsButNotAllOfTheReplayedOnes() {
172 final Collaborator collaborator = new Collaborator(0);
173
174 new Expectations(collaborator) {
175 {
176 collaborator.setValue(2);
177 collaborator.setValue(3);
178 }
179 };
180
181 collaborator.setValue(1);
182 collaborator.setValue(2);
183 collaborator.setValue(3);
184
185
186 new VerificationsInOrder() {
187 {
188
189 collaborator.setValue(2);
190 collaborator.setValue(3);
191 }
192 };
193 new FullVerifications() {
194 };
195 }
196
197
198
199
200 @Test
201 @ExpectedException(MissingInvocation.class)
202 void expectTwoInvocationsOnDynamicMockButReplayOnce() {
203 final Collaborator collaborator = new Collaborator();
204
205 new Expectations(collaborator) {
206 {
207 collaborator.getValue();
208 times = 2;
209 }
210 };
211
212 assertEquals(0, collaborator.getValue());
213 }
214
215
216
217
218 @Test
219 void expectOneInvocationOnDynamicMockButReplayTwice() {
220 final Collaborator collaborator = new Collaborator(1);
221
222 new Expectations(collaborator) {
223 {
224 collaborator.getValue();
225 times = 1;
226 }
227 };
228
229
230 assertEquals(0, collaborator.getValue());
231
232
233 Assertions.assertThrows(UnexpectedInvocation.class, () -> assertEquals(0, collaborator.getValue()));
234 }
235
236
237
238
239 @Test
240 void dynamicallyMockAnInstance() {
241 final Collaborator collaborator = new Collaborator(2);
242
243 new Expectations(collaborator) {
244 {
245 collaborator.simpleOperation(1, "", null);
246 result = false;
247 Collaborator.doSomething(anyBoolean, "test");
248 }
249 };
250
251
252 assertFalse(collaborator.simpleOperation(1, "", null));
253 Collaborator.doSomething(true, "test");
254
255
256 assertEquals(2, collaborator.getValue());
257 assertEquals(45, new Collaborator(45).value);
258 assertEquals(-1, new Collaborator().value);
259
260 try {
261 Collaborator.doSomething(false, null);
262 fail();
263 } catch (IllegalStateException ignore) {
264 }
265
266 new Verifications() {
267 {
268 collaborator.getValue();
269 times = 1;
270 }
271 };
272 }
273
274
275
276
277 @Test
278 void mockMethodInSameClass() {
279 final Collaborator collaborator = new Collaborator();
280
281 new Expectations(collaborator) {
282 {
283 collaborator.simpleOperation(1, anyString, null);
284 result = false;
285 }
286 };
287
288 assertFalse(collaborator.methodWhichCallsAnotherInTheSameClass());
289 assertTrue(collaborator.simpleOperation(2, "", null));
290 assertFalse(collaborator.simpleOperation(1, "", null));
291 }
292
293
294
295
296 static final class SubCollaborator extends Collaborator {
297
298
299
300
301 @SuppressWarnings("unused")
302 SubCollaborator() {
303 this(1);
304 }
305
306
307
308
309
310
311
312 SubCollaborator(int value) {
313 super(value);
314 }
315
316 @Override
317 String overridableMethod() {
318 return super.overridableMethod() + " overridden";
319 }
320
321
322
323
324
325
326 String format() {
327 return String.valueOf(value);
328 }
329
330
331
332
333 static void causeFailure() {
334 throw new RuntimeException();
335 }
336 }
337
338
339
340
341 @Test
342 void dynamicallyMockASubCollaboratorInstance() {
343 final SubCollaborator collaborator = new SubCollaborator();
344
345 new Expectations(collaborator) {
346 {
347 collaborator.getValue();
348 result = 5;
349 collaborator.format();
350 result = "test";
351 SubCollaborator.causeFailure();
352 }
353 };
354
355
356 assertEquals(5, collaborator.getValue());
357 SubCollaborator.causeFailure();
358 assertEquals("test", collaborator.format());
359
360
361 assertTrue(collaborator.simpleOperation(0, null, null));
362 assertEquals("1", new SubCollaborator().format());
363
364 try {
365 Collaborator.doSomething(true, null);
366 fail();
367 } catch (IllegalStateException ignore) {
368 }
369 }
370
371
372
373
374 interface Dependency {
375
376
377
378
379
380
381 boolean doSomething();
382
383
384
385
386
387
388
389
390
391 List<?> doSomethingElse(int n);
392 }
393
394
395
396
397 @Test
398 void dynamicallyMockAnAnonymousClassInstanceThroughTheImplementedInterface() {
399 final Collaborator collaborator = new Collaborator();
400
401 final Dependency dependency = new Dependency() {
402 @Override
403 public boolean doSomething() {
404 return false;
405 }
406
407 @Override
408 public List<?> doSomethingElse(int n) {
409 return null;
410 }
411 };
412
413 new Expectations(collaborator, dependency) {
414 {
415 collaborator.getValue();
416 result = 5;
417 dependency.doSomething();
418 result = true;
419 }
420 };
421
422
423 assertEquals(5, collaborator.getValue());
424 assertTrue(dependency.doSomething());
425
426
427 assertTrue(collaborator.simpleOperation(0, null, null));
428 assertNull(dependency.doSomethingElse(3));
429
430 new FullVerifications() {
431 {
432 dependency.doSomethingElse(anyInt);
433 collaborator.simpleOperation(0, null, null);
434 }
435 };
436 }
437
438
439
440
441 public interface AnotherInterface {
442 }
443
444
445
446
447 interface NonPublicInterface {
448 }
449
450
451
452
453
454
455
456
457
458 @Test
459 void attemptToUseDynamicMockingForInvalidTypes(@Mocked AnotherInterface publicInterfaceMock,
460 @Injectable NonPublicInterface nonPublicInterfaceMock) {
461 assertInvalidTypeForDynamicPartialMocking(new String[1]);
462 assertInvalidTypeForDynamicPartialMocking(123);
463 assertInvalidTypeForDynamicPartialMocking(true);
464 assertInvalidTypeForDynamicPartialMocking(2.5);
465 assertInvalidTypeForDynamicPartialMocking(publicInterfaceMock);
466 assertInvalidTypeForDynamicPartialMocking(nonPublicInterfaceMock);
467 }
468
469
470
471
472
473
474
475 void assertInvalidTypeForDynamicPartialMocking(Object object) {
476 try {
477 new Expectations(object) {
478 };
479 fail();
480 } catch (IllegalArgumentException e) {
481 assertTrue(e.getMessage().contains("partial mocking"));
482 }
483 }
484
485
486
487
488 @Test
489 void dynamicPartialMockingWithExactArgumentMatching() {
490 final Collaborator collaborator = new Collaborator();
491
492 new Expectations(collaborator) {
493 {
494 collaborator.simpleOperation(1, "s", null);
495 result = false;
496 }
497 };
498
499 assertFalse(collaborator.simpleOperation(1, "s", null));
500 assertTrue(collaborator.simpleOperation(2, "s", null));
501 assertTrue(collaborator.simpleOperation(1, "S", null));
502 assertTrue(collaborator.simpleOperation(1, "s", new Date()));
503 assertTrue(collaborator.simpleOperation(1, null, new Date()));
504 assertFalse(collaborator.simpleOperation(1, "s", null));
505
506 new FullVerifications() {
507 {
508 collaborator.simpleOperation(anyInt, null, null);
509 }
510 };
511 }
512
513
514
515
516 @Test
517 void dynamicPartialMockingWithFlexibleArgumentMatching() {
518 final Collaborator mock = new Collaborator();
519
520 new Expectations(mock) {
521 {
522 mock.simpleOperation(anyInt, withPrefix("s"), null);
523 result = false;
524 }
525 };
526
527 assertFalse(mock.simpleOperation(1, "sSs", null));
528 assertTrue(mock.simpleOperation(2, " s", null));
529 assertTrue(mock.simpleOperation(1, "S", null));
530 assertFalse(mock.simpleOperation(-1, "s", new Date()));
531 assertTrue(mock.simpleOperation(1, null, null));
532 assertFalse(mock.simpleOperation(0, "string", null));
533
534 Collaborator collaborator = new Collaborator();
535 assertTrue(collaborator.simpleOperation(1, "sSs", null));
536 assertTrue(collaborator.simpleOperation(-1, null, new Date()));
537 }
538
539
540
541
542 @Test
543 void dynamicPartialMockingWithInstanceSpecificMatching() {
544 final Collaborator collaborator1 = new Collaborator();
545 final Collaborator collaborator2 = new Collaborator(4);
546
547 new Expectations(collaborator1, collaborator2) {
548 {
549 collaborator1.getValue();
550 result = 3;
551 }
552 };
553
554 assertEquals(3, collaborator1.getValue());
555 assertEquals(4, collaborator2.getValue());
556
557 new VerificationsInOrder() {
558 {
559 collaborator1.getValue();
560 times = 1;
561 collaborator2.getValue();
562 times = 1;
563 }
564 };
565 }
566
567
568
569
570 @Test
571 void dynamicPartialMockingWithInstanceSpecificMatchingOnTwoInstancesOfSameClass() {
572 final Collaborator mock1 = new Collaborator();
573 final Collaborator mock2 = new Collaborator();
574
575 new Expectations(mock1, mock2) {
576 {
577 mock1.getValue();
578 result = 1;
579 mock2.getValue();
580 result = 2;
581 }
582 };
583
584 assertEquals(2, mock2.getValue());
585 assertEquals(1, mock1.getValue());
586 }
587
588
589
590
591 @Test
592 void methodWithNoRecordedExpectationCalledTwiceDuringReplay() {
593 final Collaborator collaborator = new Collaborator(123);
594
595 new Expectations(collaborator) {
596 };
597
598 assertEquals(123, collaborator.getValue());
599 assertEquals(123, collaborator.getValue());
600
601 new FullVerifications() {
602 {
603 collaborator.getValue();
604 times = 2;
605 }
606 };
607 }
608
609
610
611
612 static final class ClassWithNative {
613
614
615
616
617
618
619 int doSomething() {
620 return nativeMethod();
621 }
622
623
624
625
626
627
628 private native int nativeMethod();
629 }
630
631
632
633
634 @Test
635 @ExpectedException(UnsatisfiedLinkError.class)
636 void attemptToPartiallyMockNativeMethod() {
637 final ClassWithNative mock = new ClassWithNative();
638
639 new Expectations(mock) {
640 {
641
642
643 mock.nativeMethod();
644 }
645 };
646 }
647
648
649
650
651
652
653
654
655
656
657 @Test
658 void mockAnnotatedConstructor(@Mocked Collaborator mock) throws Exception {
659 Constructor<?> mockedConstructor = Collaborator.class.getDeclaredConstructor(int.class);
660
661 assertTrue(mockedConstructor.isAnnotationPresent(Deprecated.class));
662 assertTrue(mockedConstructor.getParameterAnnotations()[0][0] instanceof Deprecated);
663 }
664
665
666
667
668 static final class TestedClass {
669
670
671
672
673 TestedClass() {
674 this(true);
675 }
676
677
678
679
680
681
682
683 TestedClass(boolean value) {
684 initialize(value);
685 }
686
687
688
689
690
691
692
693 private void initialize(@SuppressWarnings("unused") boolean flag) {
694 }
695 }
696
697
698
699
700 static class BaseClass {
701
702
703
704
705
706
707 @SuppressWarnings("unused")
708 BaseClass(Object o) {
709 assert o != null;
710 }
711
712
713
714
715 BaseClass() {
716 }
717 }
718
719
720
721
722 static class SubClass extends BaseClass {
723 }
724
725
726
727
728 static class SubSubClass extends SubClass {
729 }
730
731
732
733
734
735
736
737 @Test
738 void mockClassIndirectlyExtendingBaseWhoseFirstConstructorHasMoreParametersThanTheSecondOne(
739 @Mocked SubSubClass mock) {
740 new SubClass();
741 }
742 }