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 java.util.Collections.singletonList;
9   
10  import static org.junit.jupiter.api.Assertions.assertEquals;
11  import static org.junit.jupiter.api.Assertions.assertNotNull;
12  import static org.junit.jupiter.api.Assertions.assertNotSame;
13  import static org.junit.jupiter.api.Assertions.assertNull;
14  import static org.junit.jupiter.api.Assertions.assertSame;
15  import static org.junit.jupiter.api.Assertions.assertTrue;
16  
17  import jakarta.inject.Inject;
18  import jakarta.inject.Provider;
19  import jakarta.inject.Singleton;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.concurrent.Callable;
24  
25  import mockit.integration.junit5.JMockitExtension;
26  
27  import org.junit.jupiter.api.BeforeEach;
28  import org.junit.jupiter.api.Test;
29  import org.junit.jupiter.api.extension.ExtendWith;
30  
31  /**
32   * The Class StandardDITest.
33   */
34  @ExtendWith(JMockitExtension.class)
35  class StandardDITest {
36  
37      /**
38       * The Class TestedClass.
39       */
40      public static class TestedClass {
41  
42          /** The global action. */
43          @Inject
44          static Runnable globalAction;
45  
46          /** The collaborator. */
47          private final Collaborator collaborator;
48  
49          /** The collaborator 1. */
50          @Inject
51          private Collaborator collaborator1;
52  
53          /** The collaborator 2. */
54          Collaborator collaborator2;
55  
56          /** The some value. */
57          @Inject
58          int someValue;
59  
60          /** The another value. */
61          @Inject
62          private int anotherValue;
63  
64          /** The non annotated field. */
65          String nonAnnotatedField;
66  
67          /** The non annotated generic field. */
68          Callable<String> nonAnnotatedGenericField;
69  
70          /**
71           * Instantiates a new tested class.
72           *
73           * @param collaborator
74           *            the collaborator
75           */
76          @Inject
77          public TestedClass(Collaborator collaborator) {
78              this.collaborator = collaborator;
79          }
80  
81          /**
82           * Instantiates a new tested class.
83           *
84           * @param collaborator
85           *            the collaborator
86           * @param anotherValue
87           *            the another value
88           */
89          @SuppressWarnings("unused")
90          public TestedClass(Collaborator collaborator, int anotherValue) {
91              throw new RuntimeException("Must not occur");
92          }
93      }
94  
95      /**
96       * The Class Collaborator.
97       */
98      static class Collaborator {
99          /** The b. */
100         boolean b = true;
101     }
102 
103     /** The tested 1. */
104     @Tested
105     TestedClass tested1;
106 
107     /** The collaborator. */
108     @Injectable
109     Collaborator collaborator; // for constructor injection
110 
111     /** The collaborator 1. */
112     @Injectable
113     Collaborator collaborator1; // for field injection
114 
115     /** The some value. */
116     @Injectable("123")
117     int someValue;
118 
119     /** The another value. */
120     @Injectable
121     final int anotherValue = 45;
122 
123     /** The callable. */
124     @Injectable
125     Callable<String> callable;
126 
127     /**
128      * The Class TestedClassWithNoAnnotatedConstructor.
129      */
130     static final class TestedClassWithNoAnnotatedConstructor {
131 
132         /** The value. */
133         @Inject
134         int value;
135 
136         /** The a text. */
137         @Inject
138         String aText;
139 
140         /** The another text. */
141         String anotherText;
142     }
143 
144     /** The tested 2. */
145     @Tested
146     TestedClassWithNoAnnotatedConstructor tested2;
147 
148     /** The a text. */
149     @Injectable
150     final String aText = "Abc";
151 
152     /**
153      * The Class TestedClassWithInjectOnConstructorOnly.
154      */
155     public static class TestedClassWithInjectOnConstructorOnly {
156 
157         /** The name. */
158         String name;
159 
160         /**
161          * Instantiates a new tested class with inject on constructor only.
162          */
163         @Inject
164         public TestedClassWithInjectOnConstructorOnly() {
165         }
166     }
167 
168     /** The tested 3. */
169     @Tested
170     TestedClassWithInjectOnConstructorOnly tested3;
171 
172     /**
173      * Invoke inject annotated constructor only.
174      */
175     @Test
176     void invokeInjectAnnotatedConstructorOnly() {
177         assertSame(collaborator, tested1.collaborator);
178         assertSame(collaborator1, tested1.collaborator1);
179         assertNull(tested1.collaborator2);
180         assertEquals(123, tested1.someValue);
181         assertEquals(45, tested1.anotherValue);
182 
183         assertEquals(123, tested2.value);
184     }
185 
186     /**
187      * Assign inject annotated fields and also non annotated ones.
188      *
189      * @param collaborator2
190      *            the collaborator 2
191      * @param notToBeUsed
192      *            the not to be used
193      */
194     @Test
195     void assignInjectAnnotatedFieldsAndAlsoNonAnnotatedOnes(@Injectable Collaborator collaborator2,
196             @Injectable("67") int notToBeUsed) {
197         assertSame(collaborator, tested1.collaborator);
198         assertSame(collaborator1, tested1.collaborator1);
199         assertSame(collaborator2, tested1.collaborator2);
200         assertEquals(123, tested1.someValue);
201         assertEquals(45, tested1.anotherValue);
202 
203         assertEquals(123, tested2.value);
204     }
205 
206     /**
207      * Assign annotated field even if tested class has no annotated constructor.
208      *
209      * @param value
210      *            the value
211      */
212     @Test
213     void assignAnnotatedFieldEvenIfTestedClassHasNoAnnotatedConstructor(@Injectable("123") int value) {
214         assertEquals(123, tested2.value);
215     }
216 
217     /** The action. */
218     @Injectable
219     Runnable action;
220 
221     /**
222      * Assign annotated static field during field injection.
223      */
224     @Test
225     void assignAnnotatedStaticFieldDuringFieldInjection() {
226         assertSame(action, TestedClass.globalAction);
227     }
228 
229     /**
230      * Consider annotated and non annotated fields for injection.
231      *
232      * @param text2
233      *            the text 2
234      */
235     @Test
236     void considerAnnotatedAndNonAnnotatedFieldsForInjection(@Injectable("XY") String text2) {
237         assertEquals(aText, tested2.aText);
238         assertNull(tested2.anotherText);
239         assertEquals(aText, tested3.name);
240     }
241 
242     /**
243      * The Class TestedClassWithProviders.
244      */
245     static final class TestedClassWithProviders {
246 
247         /** The port. */
248         final int port;
249 
250         /** The collaborator. */
251         final Collaborator collaborator;
252 
253         /** The user. */
254         @Inject
255         Provider<String> user;
256 
257         /** The password. */
258         @Inject
259         Provider<String> password;
260 
261         /**
262          * Instantiates a new tested class with providers.
263          *
264          * @param port
265          *            the port
266          * @param collaborator
267          *            the collaborator
268          */
269         @Inject
270         TestedClassWithProviders(Provider<Integer> port, Collaborator collaborator) {
271             this.port = port.get();
272             this.collaborator = collaborator;
273         }
274     }
275 
276     /** The tested 4. */
277     @Tested
278     TestedClassWithProviders tested4;
279 
280     /** The port number. */
281     @Injectable
282     Integer portNumber = 4567;
283 
284     /** The user. */
285     @Injectable
286     String user = "John";
287 
288     /** The password. */
289     @Injectable
290     String password = "123";
291 
292     /**
293      * Support provider fields and parameters.
294      */
295     @Test
296     void supportProviderFieldsAndParameters() {
297         assertEquals(portNumber.intValue(), tested4.port);
298         assertSame(collaborator, tested4.collaborator);
299         assertEquals(user, tested4.user.get());
300         assertEquals(password, tested4.password.get());
301     }
302 
303     /**
304      * The Class TestedClassWithVarargsParameterForProviders.
305      */
306     static final class TestedClassWithVarargsParameterForProviders {
307 
308         /** The collaborator 1. */
309         final Collaborator collaborator1;
310 
311         /** The collaborator 2. */
312         final Collaborator collaborator2;
313 
314         /** The optional collaborators. */
315         final List<Collaborator> optionalCollaborators = new ArrayList<>();
316 
317         /** The name provider. */
318         @Inject
319         Provider<String> nameProvider;
320 
321         /**
322          * Instantiates a new tested class with varargs parameter for providers.
323          *
324          * @param collaborators
325          *            the collaborators
326          */
327         @SuppressWarnings({ "unchecked", "VariableArgumentMethod" })
328         @Inject
329         TestedClassWithVarargsParameterForProviders(Provider<Collaborator>... collaborators) {
330             int n = collaborators.length;
331             assertTrue(n > 1);
332 
333             collaborator1 = collaborators[0].get();
334             assertSame(collaborator1, collaborators[0].get()); // default (singleton)
335 
336             collaborator2 = collaborators[2].get();
337             assertNull(collaborators[2].get()); // recorded
338 
339             if (n > 3) {
340                 Collaborator col = collaborators[3].get();
341                 optionalCollaborators.add(col);
342             }
343         }
344     }
345 
346     /** The tested 5. */
347     @Tested
348     TestedClassWithVarargsParameterForProviders tested5;
349 
350     /** The collaborator provider. */
351     @Injectable
352     Provider<Collaborator> collaboratorProvider;
353 
354     /** The col 3. */
355     @Injectable
356     Collaborator col3;
357 
358     /**
359      * Configure provider used by constructor of tested class.
360      */
361     @BeforeEach
362     void configureProviderUsedByConstructorOfTestedClass() {
363         new Expectations() {
364             {
365                 Collaborator[] collaborators = { col3, null };
366                 collaboratorProvider.get();
367                 result = collaborators;
368             }
369         };
370     }
371 
372     /**
373      * Support varargs parameter with providers.
374      *
375      * @param nameProvider
376      *            the name provider
377      */
378     @Test
379     void supportVarargsParameterWithProviders(@Injectable final Provider<String> nameProvider) {
380         final String[] names = { "John", "Mary" };
381         new Expectations() {
382             {
383                 nameProvider.get();
384                 result = names;
385             }
386         };
387 
388         assertSame(collaborator, tested5.collaborator1);
389         assertNotNull(tested5.collaborator2);
390         assertNotSame(tested5.collaborator1, tested5.collaborator2);
391         assertEquals(singletonList(col3), tested5.optionalCollaborators);
392 
393         assertEquals(names[0], tested5.nameProvider.get());
394         assertEquals(names[1], tested5.nameProvider.get());
395     }
396 
397     /**
398      * Fields not annotated with known DI annotations should still be injected.
399      */
400     @Test
401     void fieldsNotAnnotatedWithKnownDIAnnotationsShouldStillBeInjected() {
402         assertEquals("Abc", tested1.nonAnnotatedField);
403         assertSame(callable, tested1.nonAnnotatedGenericField);
404     }
405 
406     /**
407      * The Class DependencyToBeProvided.
408      */
409     public static final class DependencyToBeProvided {
410     }
411 
412     /**
413      * The Class TestedClassWithProvider.
414      */
415     public static final class TestedClassWithProvider {
416         /** The provider. */
417         @Inject
418         Provider<DependencyToBeProvided> provider;
419     }
420 
421     /** The tested 6. */
422     @Tested(fullyInitialized = true)
423     TestedClassWithProvider tested6;
424 
425     /**
426      * Instantiate class with dependency from standard provider.
427      */
428     @Test
429     void instantiateClassWithDependencyFromStandardProvider() {
430         DependencyToBeProvided providedDependency1 = tested6.provider.get();
431         DependencyToBeProvided providedDependency2 = tested6.provider.get();
432         assertNotNull(providedDependency1);
433         assertNotNull(providedDependency2);
434         assertNotSame(providedDependency1, providedDependency2);
435     }
436 
437     /**
438      * The Class SingletonDependencyToBeProvided.
439      */
440     @Singleton
441     public static final class SingletonDependencyToBeProvided {
442     }
443 
444     /**
445      * The Class TestedClassWithSingletonProvider.
446      */
447     public static final class TestedClassWithSingletonProvider {
448         /** The provider. */
449         @Inject
450         Provider<SingletonDependencyToBeProvided> provider;
451     }
452 
453     /** The tested 7. */
454     @Tested(fullyInitialized = true)
455     TestedClassWithSingletonProvider tested7;
456 
457     /**
458      * Instantiate class with singleton dependency from standard provider.
459      */
460     @Test
461     void instantiateClassWithSingletonDependencyFromStandardProvider() {
462         SingletonDependencyToBeProvided providedDependency1 = tested7.provider.get();
463         SingletonDependencyToBeProvided providedDependency2 = tested7.provider.get();
464         assertNotNull(providedDependency1);
465         assertNotNull(providedDependency2);
466         assertSame(providedDependency1, providedDependency2);
467     }
468 }