1 package mockit;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertFalse;
5 import static org.junit.jupiter.api.Assertions.assertNull;
6 import static org.junit.jupiter.api.Assertions.assertTrue;
7 import static org.junit.jupiter.api.Assertions.fail;
8
9 import jakarta.xml.bind.annotation.XmlElement;
10
11 import java.lang.reflect.Constructor;
12 import java.util.Date;
13 import java.util.List;
14
15 import mockit.internal.expectations.invocation.MissingInvocation;
16 import mockit.internal.expectations.invocation.UnexpectedInvocation;
17
18 import org.junit.Ignore;
19 import org.junit.Rule;
20 import org.junit.Test;
21 import org.junit.rules.ExpectedException;
22
23
24
25
26 @SuppressWarnings("deprecation")
27 public final class PartialMockingTest {
28
29
30 @Rule
31 public final ExpectedException thrown = ExpectedException.none();
32
33
34
35
36 @Deprecated
37 static class Collaborator {
38
39
40 @Deprecated
41 protected int value;
42
43
44
45
46 Collaborator() {
47 value = -1;
48 }
49
50
51
52
53
54
55
56 @Deprecated
57 Collaborator(@Deprecated int value) {
58 this.value = value;
59 }
60
61
62
63
64
65
66 final int getValue() {
67 return value;
68 }
69
70
71
72
73
74
75
76 void setValue(int value) {
77 this.value = value;
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @SuppressWarnings("unused")
93 final boolean simpleOperation(int a, @XmlElement(name = "test") String b, Date c) {
94 return true;
95 }
96
97
98
99
100
101
102
103
104
105 static void doSomething(@SuppressWarnings("unused") boolean b, @SuppressWarnings("unused") String s) {
106 throw new IllegalStateException();
107 }
108
109
110
111
112
113
114 @Ignore("test")
115 boolean methodWhichCallsAnotherInTheSameClass() {
116 return simpleOperation(1, "internal", null);
117 }
118
119
120
121
122
123
124 String overridableMethod() {
125 return "base";
126 }
127 }
128
129
130
131
132 @Test
133 public void attemptToPartiallyMockAClass() {
134 thrown.expect(IllegalArgumentException.class);
135 thrown.expectMessage("Invalid Class");
136 thrown.expectMessage("partial mocking");
137 thrown.expectMessage("Collaborator");
138
139 new Expectations(Collaborator.class) {
140 };
141 }
142
143
144
145
146 @Test
147 public void dynamicMockFullyVerified_verifyAllRecordedExpectationsButNotAllOfTheReplayedOnes() {
148 final Collaborator collaborator = new Collaborator(0);
149
150 new Expectations(collaborator) {
151 {
152 collaborator.setValue(1);
153 }
154 };
155
156 collaborator.setValue(1);
157 collaborator.setValue(2);
158
159
160 new FullVerifications() {
161
162
163 };
164 }
165
166
167
168
169 @Test
170 public void dynamicMockFullyVerifiedInOrder_verifyAllRecordedExpectationsButNotAllOfTheReplayedOnes() {
171 final Collaborator collaborator = new Collaborator(0);
172
173 new Expectations(collaborator) {
174 {
175 collaborator.setValue(2);
176 collaborator.setValue(3);
177 }
178 };
179
180 collaborator.setValue(1);
181 collaborator.setValue(2);
182 collaborator.setValue(3);
183
184
185 new VerificationsInOrder() {
186 {
187
188 collaborator.setValue(2);
189 collaborator.setValue(3);
190 }
191 };
192 new FullVerifications() {
193 };
194 }
195
196
197
198
199 @Test
200 public void expectTwoInvocationsOnDynamicMockButReplayOnce() {
201 final Collaborator collaborator = new Collaborator();
202
203 new Expectations(collaborator) {
204 {
205 collaborator.getValue();
206 times = 2;
207 }
208 };
209
210 assertEquals(0, collaborator.getValue());
211 thrown.expect(MissingInvocation.class);
212 }
213
214
215
216
217 @Test
218 public void expectOneInvocationOnDynamicMockButReplayTwice() {
219 final Collaborator collaborator = new Collaborator(1);
220
221 new Expectations(collaborator) {
222 {
223 collaborator.getValue();
224 times = 1;
225 }
226 };
227
228
229 assertEquals(0, collaborator.getValue());
230
231
232 thrown.expect(UnexpectedInvocation.class);
233 assertEquals(0, collaborator.getValue());
234 }
235
236
237
238
239 @Test
240 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public 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 public void attemptToPartiallyMockNativeMethod() {
636 thrown.expect(UnsatisfiedLinkError.class);
637
638 final ClassWithNative mock = new ClassWithNative();
639
640 new Expectations(mock) {
641 {
642
643
644
645 mock.nativeMethod();
646 }
647 };
648 }
649
650
651
652
653
654
655
656
657
658
659 @Test
660 public void mockAnnotatedConstructor(@Mocked Collaborator mock) throws Exception {
661 Constructor<?> mockedConstructor = Collaborator.class.getDeclaredConstructor(int.class);
662
663 assertTrue(mockedConstructor.isAnnotationPresent(Deprecated.class));
664 assertTrue(mockedConstructor.getParameterAnnotations()[0][0] instanceof Deprecated);
665 }
666
667
668
669
670 static final class TestedClass {
671
672
673
674
675 TestedClass() {
676 this(true);
677 }
678
679
680
681
682
683
684
685 TestedClass(boolean value) {
686 initialize(value);
687 }
688
689
690
691
692
693
694
695 private void initialize(@SuppressWarnings("unused") boolean flag) {
696 }
697 }
698
699
700
701
702 static class BaseClass {
703
704
705
706
707
708
709 @SuppressWarnings("unused")
710 BaseClass(Object o) {
711 assert o != null;
712 }
713
714
715
716
717 BaseClass() {
718 }
719 }
720
721
722
723
724 static class SubClass extends BaseClass {
725 }
726
727
728
729
730 static class SubSubClass extends SubClass {
731 }
732
733
734
735
736
737
738
739 @Test
740 public void mockClassIndirectlyExtendingBaseWhoseFirstConstructorHasMoreParametersThanTheSecondOne(
741 @Mocked SubSubClass mock) {
742 new SubClass();
743 }
744 }