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.assertNotNull;
11 import static org.junit.jupiter.api.Assertions.assertNotSame;
12 import static org.junit.jupiter.api.Assertions.assertNull;
13 import static org.junit.jupiter.api.Assertions.assertSame;
14 import static org.junit.jupiter.api.Assertions.assertTrue;
15 import static org.junit.jupiter.api.Assertions.fail;
16
17 import jakarta.annotation.PostConstruct;
18 import jakarta.annotation.PreDestroy;
19 import jakarta.annotation.Resource;
20 import jakarta.ejb.EJB;
21 import jakarta.inject.Inject;
22 import jakarta.persistence.Cache;
23 import jakarta.persistence.CacheRetrieveMode;
24 import jakarta.persistence.CacheStoreMode;
25 import jakarta.persistence.ConnectionConsumer;
26 import jakarta.persistence.ConnectionFunction;
27 import jakarta.persistence.EntityGraph;
28 import jakarta.persistence.EntityManager;
29 import jakarta.persistence.EntityManagerFactory;
30 import jakarta.persistence.EntityTransaction;
31 import jakarta.persistence.FindOption;
32 import jakarta.persistence.FlushModeType;
33 import jakarta.persistence.LockModeType;
34 import jakarta.persistence.LockOption;
35 import jakarta.persistence.Persistence;
36 import jakarta.persistence.PersistenceContext;
37 import jakarta.persistence.PersistenceUnit;
38 import jakarta.persistence.PersistenceUnitTransactionType;
39 import jakarta.persistence.PersistenceUnitUtil;
40 import jakarta.persistence.Query;
41 import jakarta.persistence.RefreshOption;
42 import jakarta.persistence.SchemaManager;
43 import jakarta.persistence.StoredProcedureQuery;
44 import jakarta.persistence.SynchronizationType;
45 import jakarta.persistence.TypedQuery;
46 import jakarta.persistence.TypedQueryReference;
47 import jakarta.persistence.criteria.CriteriaBuilder;
48 import jakarta.persistence.criteria.CriteriaDelete;
49 import jakarta.persistence.criteria.CriteriaQuery;
50 import jakarta.persistence.criteria.CriteriaSelect;
51 import jakarta.persistence.criteria.CriteriaUpdate;
52 import jakarta.persistence.metamodel.Metamodel;
53 import jakarta.servlet.ServletContext;
54 import jakarta.servlet.http.HttpSession;
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.io.Writer;
59 import java.net.URI;
60 import java.net.URISyntaxException;
61 import java.nio.charset.StandardCharsets;
62 import java.nio.file.Files;
63 import java.nio.file.Path;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.function.Consumer;
67 import java.util.function.Function;
68
69 import mockit.integration.junit5.JMockitExtension;
70
71 import org.junit.jupiter.api.AfterAll;
72 import org.junit.jupiter.api.AfterEach;
73 import org.junit.jupiter.api.BeforeAll;
74 import org.junit.jupiter.api.MethodOrderer.MethodName;
75 import org.junit.jupiter.api.Test;
76 import org.junit.jupiter.api.TestMethodOrder;
77 import org.junit.jupiter.api.extension.ExtendWith;
78
79
80
81
82 @ExtendWith(JMockitExtension.class)
83 @TestMethodOrder(MethodName.class)
84 class TestedClassWithFullStandardDITest {
85
86
87
88
89 public static class TestedClass {
90
91
92 @Inject
93 private Runnable dependencyToBeMocked;
94
95
96 @Inject
97 private FirstLevelDependency dependency2;
98
99
100 @Resource
101 private FirstLevelDependency dependency3;
102
103
104 @Inject
105 private CommonDependency commonDependency;
106
107
108 String text;
109
110
111 boolean initialized;
112
113
114 static boolean destroyed;
115
116
117
118
119 @PostConstruct
120 void initialize() {
121 assertNotNull(dependency3);
122 initialized = true;
123 }
124
125
126
127
128 @PreDestroy
129 void destroy() {
130 assertTrue(initialized, "TestedClass not initialized");
131 destroyed = true;
132 }
133 }
134
135
136
137
138 static final class AnotherTestedClass {
139
140
141 @PersistenceContext
142 EntityManager em;
143
144
145 @Inject
146 HttpSession session;
147
148
149 @Inject
150 ServletContext applicationContext;
151 }
152
153
154
155
156 public static class FirstLevelDependency {
157
158
159 @EJB
160 private SecondLevelDependency dependency;
161
162
163 @Inject
164 private static SecondLevelDependency staticDependency;
165
166
167 @Inject
168 private CommonDependency commonDependency;
169
170
171 @Resource
172 private static Runnable dependencyToBeMocked;
173
174
175 @PersistenceContext
176 private EntityManager em;
177 }
178
179
180
181
182 public static class SecondLevelDependency {
183
184
185 @Inject
186 CommonDependency commonDependency;
187
188
189 @PersistenceContext
190 private EntityManager em;
191
192
193 @Inject
194 ServletContext servletContext;
195
196
197 @Inject
198 HttpSession httpSession;
199
200
201 boolean initialized;
202
203
204 static boolean terminated;
205
206
207
208
209 @PostConstruct
210 void initialize() {
211 initialized = true;
212 }
213
214
215
216
217 @PreDestroy
218 void terminate() {
219 terminated = true;
220 }
221 }
222
223
224
225
226 public static class CommonDependency {
227
228
229 @PersistenceUnit(unitName = "test")
230 private EntityManagerFactory emFactory;
231
232
233 @PersistenceContext(unitName = "test")
234 private EntityManager em;
235 }
236
237
238 @Tested(fullyInitialized = true)
239 TestedClass tested;
240
241
242 @Tested(fullyInitialized = true)
243 AnotherTestedClass tested2;
244
245
246 @Injectable
247 Runnable mockedDependency;
248
249
250 static File persistenceXmlFile;
251
252
253 static EntityManagerFactory namedEMFactory;
254
255
256 static EntityManager namedEM;
257
258
259 static EntityManagerFactory defaultEMFactory;
260
261
262 static EntityManager defaultEM;
263
264
265
266
267
268
269
270 @BeforeAll
271 @SuppressWarnings("rawtypes")
272 static void setUpPersistence() throws Exception {
273 final class FakeEntityManager implements EntityManager {
274 @Override
275 public void persist(Object entity) {
276 }
277
278 @Override
279 public <T> T merge(T entity) {
280 return null;
281 }
282
283 @Override
284 public void remove(Object entity) {
285 }
286
287 @Override
288 public <T> T find(Class<T> entityClass, Object primaryKey) {
289 return null;
290 }
291
292 @Override
293 public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
294 return null;
295 }
296
297 @Override
298 public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
299 return null;
300 }
301
302 @Override
303 public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode,
304 Map<String, Object> properties) {
305 return null;
306 }
307
308 @Override
309 public <T> T getReference(Class<T> entityClass, Object primaryKey) {
310 return null;
311 }
312
313 @Override
314 public void flush() {
315 }
316
317 @Override
318 public void setFlushMode(FlushModeType flushMode) {
319 }
320
321 @Override
322 public FlushModeType getFlushMode() {
323 return null;
324 }
325
326 @Override
327 public void lock(Object entity, LockModeType lockMode) {
328 }
329
330 @Override
331 public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
332 }
333
334 @Override
335 public void refresh(Object entity) {
336 }
337
338 @Override
339 public void refresh(Object entity, Map<String, Object> properties) {
340 }
341
342 @Override
343 public void refresh(Object entity, LockModeType lockMode) {
344 }
345
346 @Override
347 public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
348 }
349
350 @Override
351 public void clear() {
352 }
353
354 @Override
355 public void detach(Object entity) {
356 }
357
358 @Override
359 public boolean contains(Object entity) {
360 return false;
361 }
362
363 @Override
364 public LockModeType getLockMode(Object entity) {
365 return null;
366 }
367
368 @Override
369 public void setProperty(String propertyName, Object value) {
370 }
371
372 @Override
373 public Map<String, Object> getProperties() {
374 return null;
375 }
376
377 @Override
378 public Query createQuery(String qlString) {
379 return null;
380 }
381
382 @Override
383 public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
384 return null;
385 }
386
387 @Override
388 public Query createQuery(CriteriaUpdate updateQuery) {
389 return null;
390 }
391
392 @Override
393 public Query createQuery(CriteriaDelete deleteQuery) {
394 return null;
395 }
396
397 @Override
398 public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
399 return null;
400 }
401
402 @Override
403 public Query createNamedQuery(String name) {
404 return null;
405 }
406
407 @Override
408 public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
409 return null;
410 }
411
412 @Override
413 public Query createNativeQuery(String sqlString) {
414 return null;
415 }
416
417 @Override
418 public Query createNativeQuery(String sqlString, Class resultClass) {
419 return null;
420 }
421
422 @Override
423 public Query createNativeQuery(String sqlString, String resultSetMapping) {
424 return null;
425 }
426
427 @Override
428 public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
429 return null;
430 }
431
432 @Override
433 public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
434 return null;
435 }
436
437 @Override
438 public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
439 return null;
440 }
441
442 @Override
443 public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
444 return null;
445 }
446
447 @Override
448 public void joinTransaction() {
449 }
450
451 @Override
452 public boolean isJoinedToTransaction() {
453 return false;
454 }
455
456 @Override
457 public <T> T unwrap(Class<T> cls) {
458 return null;
459 }
460
461 @Override
462 public Object getDelegate() {
463 return null;
464 }
465
466 @Override
467 public void close() {
468 }
469
470 @Override
471 public boolean isOpen() {
472 return false;
473 }
474
475 @Override
476 public EntityTransaction getTransaction() {
477 return null;
478 }
479
480 @Override
481 public EntityManagerFactory getEntityManagerFactory() {
482 return null;
483 }
484
485 @Override
486 public CriteriaBuilder getCriteriaBuilder() {
487 return null;
488 }
489
490 @Override
491 public Metamodel getMetamodel() {
492 return null;
493 }
494
495 @Override
496 public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
497 return null;
498 }
499
500 @Override
501 public EntityGraph<?> createEntityGraph(String graphName) {
502 return null;
503 }
504
505 @Override
506 public EntityGraph<?> getEntityGraph(String graphName) {
507 return null;
508 }
509
510 @Override
511 public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
512 return null;
513 }
514
515 @Override
516 public <T> T find(Class<T> entityClass, Object primaryKey, FindOption... options) {
517 return null;
518 }
519
520 @Override
521 public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) {
522 return null;
523 }
524
525 @Override
526 public <T> T getReference(T entity) {
527 return null;
528 }
529
530 @Override
531 public void lock(Object entity, LockModeType lockMode, LockOption... options) {
532 }
533
534 @Override
535 public void refresh(Object entity, RefreshOption... options) {
536 }
537
538 @Override
539 public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) {
540 }
541
542 @Override
543 public void setCacheStoreMode(CacheStoreMode cacheStoreMode) {
544 }
545
546 @Override
547 public CacheRetrieveMode getCacheRetrieveMode() {
548 return null;
549 }
550
551 @Override
552 public CacheStoreMode getCacheStoreMode() {
553 return null;
554 }
555
556 @Override
557 public <T> TypedQuery<T> createQuery(CriteriaSelect<T> selectQuery) {
558 return null;
559 }
560
561 @Override
562 public <T> TypedQuery<T> createQuery(TypedQueryReference<T> reference) {
563 return null;
564 }
565
566 @Override
567 public <C> void runWithConnection(ConnectionConsumer<C> action) {
568 }
569
570 @Override
571 public <C, T> T callWithConnection(ConnectionFunction<C, T> function) {
572 return null;
573 }
574 }
575 namedEM = new FakeEntityManager();
576 defaultEM = new FakeEntityManager();
577
578 final class FakeEntityManagerFactory implements EntityManagerFactory {
579 final EntityManager em;
580
581 FakeEntityManagerFactory(EntityManager em) {
582 this.em = em;
583 }
584
585 @Override
586 public EntityManager createEntityManager() {
587 return em;
588 }
589
590 @Override
591 public EntityManager createEntityManager(Map map) {
592 return null;
593 }
594
595 @Override
596 public EntityManager createEntityManager(SynchronizationType synchronizationType) {
597 return null;
598 }
599
600 @Override
601 public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) {
602 return null;
603 }
604
605 @Override
606 public CriteriaBuilder getCriteriaBuilder() {
607 return null;
608 }
609
610 @Override
611 public Metamodel getMetamodel() {
612 return null;
613 }
614
615 @Override
616 public boolean isOpen() {
617 return false;
618 }
619
620 @Override
621 public void close() {
622 }
623
624 @Override
625 public Map<String, Object> getProperties() {
626 return null;
627 }
628
629 @Override
630 public Cache getCache() {
631 return null;
632 }
633
634 @Override
635 public PersistenceUnitUtil getPersistenceUnitUtil() {
636 return null;
637 }
638
639 @Override
640 public void addNamedQuery(String name, Query query) {
641 }
642
643 @Override
644 public <T> T unwrap(Class<T> cls) {
645 return null;
646 }
647
648 @Override
649 public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) {
650 }
651
652 @Override
653 public String getName() {
654 return null;
655 }
656
657 @Override
658 public PersistenceUnitTransactionType getTransactionType() {
659 return null;
660 }
661
662 @Override
663 public SchemaManager getSchemaManager() {
664 return null;
665 }
666
667 @Override
668 public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType) {
669 return null;
670 }
671
672 @Override
673 public <E> Map<String, EntityGraph<? extends E>> getNamedEntityGraphs(Class<E> entityType) {
674 return null;
675 }
676
677 @Override
678 public void runInTransaction(Consumer<EntityManager> work) {
679 }
680
681 @Override
682 public <R> R callInTransaction(Function<EntityManager, R> work) {
683 return null;
684 }
685 }
686 namedEMFactory = new FakeEntityManagerFactory(namedEM);
687 defaultEMFactory = new FakeEntityManagerFactory(defaultEM);
688
689 new MockUp<Persistence>() {
690 @Mock
691 EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) {
692 if ("test".equals(persistenceUnitName)) {
693 return namedEMFactory;
694 }
695
696 if ("default".equals(persistenceUnitName)) {
697 return defaultEMFactory;
698 }
699
700 fail("Unexpected persistence unit");
701 return null;
702 }
703 };
704
705 createTemporaryPersistenceXmlFileWithDefaultPersistenceUnit();
706 }
707
708
709
710
711
712
713
714
715
716 static void createTemporaryPersistenceXmlFileWithDefaultPersistenceUnit() throws IOException, URISyntaxException {
717 URI rootOfClasspath = TestedClass.class.getProtectionDomain().getCodeSource().getLocation().toURI();
718 File tempFolder = Path.of(rootOfClasspath).resolve("META-INF").toFile();
719 if (tempFolder.mkdir()) {
720 tempFolder.deleteOnExit();
721 }
722
723 persistenceXmlFile = tempFolder.toPath().resolve("persistence.xml").toFile();
724
725 Writer xmlWriter = Files.newBufferedWriter(persistenceXmlFile.toPath(), StandardCharsets.UTF_8);
726 xmlWriter.write("<persistence><persistence-unit name='default'/></persistence>");
727 xmlWriter.close();
728 }
729
730
731
732
733 @AfterAll
734 static void deleteDefaultPersistenceXmlFile() {
735 persistenceXmlFile.delete();
736 persistenceXmlFile.getParentFile().delete();
737 }
738
739
740
741
742 @Test
743 void useFullyInitializedTestedObject() {
744
745 assertSame(mockedDependency, tested.dependencyToBeMocked);
746 assertNotNull(tested.dependency2);
747 assertSame(tested.dependency2, tested.dependency3);
748 assertNotNull(tested.commonDependency);
749 assertNull(tested.text);
750
751
752 assertNotNull(tested.dependency2.dependency);
753 assertSame(FirstLevelDependency.staticDependency, tested.dependency2.dependency);
754 assertSame(tested.dependency3.dependency, tested.dependency2.dependency);
755 assertSame(tested.commonDependency, tested.dependency2.commonDependency);
756 assertSame(tested.commonDependency, tested.dependency3.commonDependency);
757 assertSame(mockedDependency, FirstLevelDependency.dependencyToBeMocked);
758 assertSame(mockedDependency, FirstLevelDependency.dependencyToBeMocked);
759 assertSame(defaultEM, tested.dependency2.em);
760 assertSame(tested.dependency2.em, tested.dependency3.em);
761 assertSame(namedEMFactory, tested.commonDependency.emFactory);
762 assertSame(namedEM, tested.commonDependency.em);
763 assertNotSame(tested.dependency2.em, tested.commonDependency.em);
764 assertSame(tested2.em, tested.dependency2.em);
765
766
767 assertSame(tested.commonDependency, tested.dependency2.dependency.commonDependency);
768 assertSame(tested.dependency2.em, tested.dependency2.dependency.em);
769
770
771 assertTrue(tested.initialized);
772 assertTrue(tested.dependency2.dependency.initialized);
773 }
774
775
776
777
778 @Test
779 void useFullyInitializedTestedObjectAgain() {
780 assertNull(tested.text);
781 }
782
783
784
785
786 @Test
787 void verifyEmulatedHttpSession() {
788 HttpSession session = tested2.session;
789 assertFalse(session.isNew());
790 assertFalse(session.getId().isEmpty());
791 assertTrue(session.getCreationTime() > 0);
792 assertTrue(session.getLastAccessedTime() > 0);
793 assertFalse(session.getAttributeNames().hasMoreElements());
794
795 session.setMaxInactiveInterval(600);
796 assertEquals(600, session.getMaxInactiveInterval());
797
798 session.setAttribute("test", 123);
799 assertEquals(123, session.getAttribute("test"));
800 assertEquals("test", session.getAttributeNames().nextElement());
801
802 session.removeAttribute("test");
803 assertNull(session.getAttribute("test"));
804
805 session.setAttribute("test2", "abc");
806 session.invalidate();
807
808 try {
809 session.isNew();
810 fail();
811 } catch (IllegalStateException invalidatedSession) {
812 }
813 try {
814 session.getCreationTime();
815 fail();
816 } catch (IllegalStateException invalidatedSession) {
817 }
818 try {
819 session.getLastAccessedTime();
820 fail();
821 } catch (IllegalStateException invalidatedSession) {
822 }
823 try {
824 session.getAttributeNames();
825 fail();
826 } catch (IllegalStateException invalidatedSession) {
827 }
828 try {
829 session.getAttribute("test2");
830 fail();
831 } catch (IllegalStateException invalidatedSession) {
832 }
833 try {
834 session.setAttribute("x", "");
835 fail();
836 } catch (IllegalStateException invalidatedSession) {
837 }
838 try {
839 session.removeAttribute("x");
840 fail();
841 } catch (IllegalStateException invalidatedSession) {
842 }
843 try {
844 session.invalidate();
845 fail();
846 } catch (IllegalStateException invalidatedSession) {
847 }
848
849 assertSame(tested2.applicationContext, session.getServletContext());
850 assertSame(session, tested.dependency3.dependency.httpSession);
851 }
852
853
854
855
856 @Test
857 void verifyEmulatedServletContext() {
858 ServletContext ctx = tested2.applicationContext;
859
860 assertFalse(ctx.getAttributeNames().hasMoreElements());
861
862 ctx.setInitParameter("test", "abc");
863 assertEquals("abc", ctx.getInitParameter("test"));
864 assertEquals("test", ctx.getInitParameterNames().nextElement());
865
866 ctx.setAttribute("test", 123);
867 assertEquals(123, ctx.getAttribute("test"));
868 assertEquals("test", ctx.getAttributeNames().nextElement());
869
870 ctx.removeAttribute("test");
871 assertNull(ctx.getAttribute("test"));
872
873 assertSame(ctx, tested.dependency2.dependency.servletContext);
874 }
875
876
877
878
879 @AfterEach
880 void verifyThatTestedFieldsWereClearedAndPreDestroyMethodsWereExecuted() {
881 assertNull(tested);
882 assertNull(tested2);
883 assertTrue(TestedClass.destroyed);
884 assertTrue(SecondLevelDependency.terminated);
885 }
886
887
888
889
890 @AfterEach
891 void clearEntityManagers() {
892 namedEM = null;
893 defaultEM = null;
894 }
895 }