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.assertNull;
10  import static org.junit.jupiter.api.Assertions.assertSame;
11  import static org.junit.jupiter.api.Assertions.fail;
12  
13  import jakarta.annotation.Resource;
14  import jakarta.inject.Inject;
15  
16  import mockit.integration.junit5.ExpectedException;
17  import mockit.integration.junit5.JMockitExtension;
18  
19  import org.junit.jupiter.api.MethodOrderer;
20  import org.junit.jupiter.api.Test;
21  import org.junit.jupiter.api.TestMethodOrder;
22  import org.junit.jupiter.api.extension.ExtendWith;
23  import org.springframework.beans.factory.annotation.Autowired;
24  import org.springframework.beans.factory.annotation.Value;
25  
26  /**
27   * The Class TestedClassWithAnnotatedDITest.
28   */
29  @ExtendWith(JMockitExtension.class)
30  @TestMethodOrder(MethodOrderer.MethodName.class)
31  class TestedClassWithAnnotatedDITest {
32  
33      /**
34       * The Class TestedClass1.
35       */
36      static class TestedClass1 {
37  
38          /** The action 2. */
39          @Resource(name = "secondAction")
40          Runnable action2;
41  
42          /** The some value. */
43          @Autowired
44          int someValue;
45  
46          /** The action 1. */
47          @Resource(name = "firstAction")
48          Runnable action1;
49  
50          /** The action 3. */
51          @Resource(name = "thirdAction")
52          Runnable action3;
53  
54          /** The another value. */
55          @Inject
56          int anotherValue;
57  
58          /** The string field with value. */
59          // @Value is supported implicitly (no specific handling for it).
60          @Value("textValue")
61          String stringFieldWithValue;
62  
63          /** The numeric field with value. */
64          @Value("123.45")
65          double numericFieldWithValue;
66  
67          /** The system property. */
68          @Value("#{systemProperties.someProperty}")
69          String systemProperty;
70  
71          /** The an int. */
72          @Value("${anotherSystemProperty}")
73          int anInt;
74  
75          /** The a long value. */
76          @Value("${propertyWithDefault:12345}")
77          long aLongValue; // default value is ignored, left as 0 if no @Injectable or @Tested is found
78      }
79  
80      /**
81       * The Class TestedClass2.
82       */
83      static class TestedClass2 {
84  
85          /** The some value. */
86          final int someValue;
87  
88          /** The action. */
89          final Runnable action;
90  
91          /** The another action. */
92          @Resource
93          Runnable anotherAction;
94  
95          /** The text. */
96          String text;
97  
98          /** The another text. */
99          @Inject
100         String anotherText;
101 
102         /** The optional action. */
103         @Autowired(required = false)
104         Runnable optionalAction;
105 
106         /**
107          * Instantiates a new tested class 2.
108          *
109          * @param someValue
110          *            the some value
111          * @param action
112          *            the action
113          * @param textValue
114          *            the text value
115          */
116         @Autowired
117         TestedClass2(int someValue, Runnable action, String textValue) {
118             this.someValue = someValue;
119             this.action = action;
120             text = textValue;
121         }
122     }
123 
124     /** The tested 1. */
125     @Tested
126     TestedClass1 tested1;
127 
128     /** The tested 2. */
129     @Tested
130     TestedClass2 tested2;
131 
132     /** The first action. */
133     @Injectable
134     Runnable firstAction;
135 
136     /** The some value. */
137     @Injectable
138     final int someValue = 1;
139 
140     /** The action. */
141     @Injectable
142     Runnable action;
143 
144     /** The text value. */
145     @Injectable
146     String textValue = "test";
147 
148     /** The another text. */
149     @Injectable
150     String anotherText = "name2";
151 
152     /** The action 3. */
153     @Injectable
154     Runnable action3; // matches @Resource(name = "thirdAction") by field name, after failing to match on "thirdAction"
155 
156     /**
157      * Inject all annotated injection points.
158      *
159      * @param anotherValue
160      *            the another value
161      * @param secondAction
162      *            the second action
163      * @param anotherAction
164      *            the another action
165      * @param unused
166      *            the unused
167      * @param stringFieldWithValue
168      *            the string field with value
169      * @param numericFieldWithValue
170      *            the numeric field with value
171      * @param systemProperty
172      *            the system property
173      * @param anInt
174      *            the an int
175      * @param aLong
176      *            the a long
177      */
178     @Test
179     void injectAllAnnotatedInjectionPoints(@Injectable("2") int anotherValue, @Injectable Runnable secondAction,
180             @Injectable Runnable anotherAction, @Injectable("true") boolean unused,
181             @Injectable("test") String stringFieldWithValue, @Injectable("123.45") double numericFieldWithValue,
182             @Injectable("propertyValue") String systemProperty, @Injectable("123") int anInt,
183             @Injectable("987654") long aLong) {
184         assertSame(firstAction, tested1.action1);
185         assertSame(secondAction, tested1.action2);
186         assertSame(action3, tested1.action3);
187         assertEquals(1, tested1.someValue);
188         assertEquals(2, tested1.anotherValue);
189         assertEquals("test", tested1.stringFieldWithValue);
190         assertEquals(123.45, tested1.numericFieldWithValue, 0);
191         assertEquals("propertyValue", tested1.systemProperty);
192         assertEquals(123, tested1.anInt);
193         assertEquals(987654, tested1.aLongValue);
194 
195         assertEquals(1, tested2.someValue);
196         assertSame(action, tested2.action);
197         assertSame(anotherAction, tested2.anotherAction);
198         assertSame(textValue, tested2.text);
199         assertSame(anotherText, tested2.anotherText);
200         assertNull(tested2.optionalAction);
201     }
202 
203     /**
204      * Leave value annotated injection points with default initialization value.
205      *
206      * @param action2
207      *            the action 2
208      * @param anotherAction
209      *            the another action
210      * @param anotherValue
211      *            the another value
212      */
213     @Test
214     void leaveValueAnnotatedInjectionPointsWithDefaultInitializationValue(@Injectable Runnable action2,
215             @Injectable Runnable anotherAction, @Injectable("2") int anotherValue) {
216         assertNull(tested1.systemProperty);
217         assertEquals(0, tested1.anInt);
218         assertEquals(0, tested1.aLongValue);
219     }
220 
221     /**
222      * Fail for annotated field which lacks an injectable.
223      */
224     @Test
225     @ExpectedException(IllegalStateException.class)
226     void failForAnnotatedFieldWhichLacksAnInjectable() {
227         fail("Must fail before starting");
228     }
229 
230     /**
231      * Fail for annotated field having an injectable of the same type which was already consumed.
232      *
233      * @param secondAction
234      *            the second action
235      */
236     @Test
237     @ExpectedException(IllegalStateException.class)
238     void failForAnnotatedFieldHavingAnInjectableOfTheSameTypeWhichWasAlreadyConsumed(
239             @Injectable Runnable secondAction) {
240         fail("Must fail before starting");
241     }
242 }