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.integration.springframework;
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.assertSame;
12  import static org.junit.jupiter.api.Assertions.assertThrows;
13  
14  import mockit.Injectable;
15  import mockit.Tested;
16  
17  import org.junit.jupiter.api.BeforeAll;
18  import org.junit.jupiter.api.Test;
19  import org.springframework.beans.factory.BeanFactory;
20  import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
21  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
22  import org.springframework.beans.factory.annotation.Autowired;
23  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
24  
25  final class SpringIntegrationTest {
26      @BeforeAll
27      static void applySpringIntegration() {
28          new FakeBeanFactory();
29      }
30  
31      public static class ExampleSUT {
32          @Autowired
33          Collaborator collaborator;
34          @Autowired
35          Dependency dependency;
36      }
37  
38      public interface Dependency {
39      }
40  
41      static final class DependencyImpl implements Dependency {
42      }
43  
44      public interface AnotherDependency {
45      }
46  
47      static final class AnotherDependencyImpl implements AnotherDependency {
48          Dependency subDep;
49      }
50  
51      static class Collaborator {
52          @Autowired
53          Runnable action;
54      }
55  
56      @Tested
57      DependencyImpl dependency;
58      @Tested(fullyInitialized = true)
59      ExampleSUT exampleSUT;
60      @Injectable
61      Runnable action;
62  
63      @Tested
64      Class<?> resolveAnotherDependency(Class<? extends AnotherDependency> anInterface) {
65          assertSame(AnotherDependency.class, anInterface);
66          return AnotherDependencyImpl.class;
67      }
68  
69      @Test
70      void lookupTestedObjectsAndInjectedDependenciesThroughTheBeanFactory() {
71          BeanFactory beanFactory = new DefaultListableBeanFactory();
72          assertTestedObjectsAndDependencies(beanFactory);
73      }
74  
75      @Test
76      void lookupTestedObjectsAndInjectedDependenciesThroughTheWebApplicationContext() {
77          BeanFactory beanFactory = new TestWebApplicationContext();
78          assertTestedObjectsAndDependencies(beanFactory);
79      }
80  
81      @Test
82      void lookUpBeanByNameWithUnknownNameUsingBeanFactory() {
83          BeanFactory beanFactory = new DefaultListableBeanFactory();
84          assertNoSuchBeanDefinitionForUnknownBeanName(beanFactory);
85      }
86  
87      @Test
88      void lookUpBeanByNameWithUnknownNameUsingWebApplicationContext() {
89          BeanFactory beanFactory = new TestWebApplicationContext();
90          assertNoSuchBeanDefinitionForUnknownBeanName(beanFactory);
91      }
92  
93      @Test
94      void lookUpBeanByNameAndTypeWithUnknownNameAndTypeUsingBeanFactory() {
95          BeanFactory beanFactory = new DefaultListableBeanFactory();
96          assertNoSuchBeanDefinitionForUnknownBeanNameAndType(beanFactory);
97      }
98  
99      @Test
100     void lookUpBeanByNameAndTypeWithUnknownNameAndTypeUsingWebApplicationContext() {
101         BeanFactory beanFactory = new TestWebApplicationContext();
102         assertNoSuchBeanDefinitionForUnknownBeanNameAndType(beanFactory);
103     }
104 
105     @Test
106     void lookUpBeanByNameAndTypeWithWrongTypeUsingBeanFactory() {
107         BeanFactory beanFactory = new DefaultListableBeanFactory();
108         assertBeanNotOfRequiredTypeForWrongBeanType(beanFactory);
109     }
110 
111     @Test
112     void lookUpBeanByNameAndTypeWithWrongTypeUsingWebApplicationContext() {
113         BeanFactory beanFactory = new TestWebApplicationContext();
114         assertBeanNotOfRequiredTypeForWrongBeanType(beanFactory);
115     }
116 
117     @SuppressWarnings("ReuseOfLocalVariable")
118     void assertTestedObjectsAndDependencies(BeanFactory beanFactory) {
119         assertSame(dependency, exampleSUT.dependency);
120 
121         // Look-up beans by name only.
122         Dependency dependencyBean = (Dependency) beanFactory.getBean("dependency");
123         assertSame(dependency, dependencyBean);
124 
125         Collaborator collaboratorBean = (Collaborator) beanFactory.getBean("collaborator");
126         assertSame(exampleSUT.collaborator, collaboratorBean);
127         assertSame(action, exampleSUT.collaborator.action);
128 
129         ExampleSUT sut = (ExampleSUT) beanFactory.getBean("exampleSUT");
130         assertSame(exampleSUT, sut);
131 
132         // Look-up beans by name and type.
133         dependencyBean = beanFactory.getBean("dependency", Dependency.class);
134         assertSame(dependency, dependencyBean);
135 
136         collaboratorBean = beanFactory.getBean("collaborator", Collaborator.class);
137         assertSame(exampleSUT.collaborator, collaboratorBean);
138 
139         sut = beanFactory.getBean("exampleSUT", ExampleSUT.class);
140         assertSame(exampleSUT, sut);
141 
142         AnotherDependency anotherDependencyBean = beanFactory.getBean("anotherDependency", AnotherDependency.class);
143         assertNotNull(anotherDependencyBean);
144 
145         // Look-up beans by type only.
146         dependencyBean = beanFactory.getBean(Dependency.class);
147         assertSame(dependency, dependencyBean);
148 
149         collaboratorBean = beanFactory.getBean(Collaborator.class);
150         assertSame(exampleSUT.collaborator, collaboratorBean);
151 
152         sut = beanFactory.getBean(ExampleSUT.class);
153         assertSame(exampleSUT, sut);
154 
155         anotherDependencyBean = beanFactory.getBean(AnotherDependency.class);
156         assertNotNull(anotherDependencyBean);
157         assertSame(dependency, ((AnotherDependencyImpl) anotherDependencyBean).subDep);
158     }
159 
160     void assertNoSuchBeanDefinitionForUnknownBeanName(BeanFactory beanFactory) {
161         Throwable throwable = assertThrows(NoSuchBeanDefinitionException.class, () -> {
162             beanFactory.getBean("undefined");
163         });
164         assertEquals("No bean named 'undefined' available", throwable.getMessage());
165     }
166 
167     void assertNoSuchBeanDefinitionForUnknownBeanNameAndType(BeanFactory beanFactory) {
168         Throwable throwable = assertThrows(NoSuchBeanDefinitionException.class, () -> {
169             beanFactory.getBean("undefined", Process.class);
170         });
171         assertEquals("No qualifying bean of type 'java.lang.Process' available: with bean name \"undefined\"",
172                 throwable.getMessage());
173     }
174 
175     void assertBeanNotOfRequiredTypeForWrongBeanType(BeanFactory beanFactory) {
176         Throwable throwable = assertThrows(BeanNotOfRequiredTypeException.class, () -> {
177             beanFactory.getBean("dependency", Collaborator.class);
178         });
179         assertEquals("Bean named 'dependency' is expected to be of type "
180                 + "'mockit.integration.springframework.SpringIntegrationTest$Collaborator' "
181                 + "but was actually of type 'mockit.integration.springframework.SpringIntegrationTest$DependencyImpl'",
182                 throwable.getMessage());
183     }
184 
185     @Test
186     void lookUpBeanByTypeHavingInjectableInstance(@Injectable Collaborator collaborator) {
187         BeanFactory beanFactory = new DefaultListableBeanFactory();
188 
189         Collaborator collaboratorBean = beanFactory.getBean(Collaborator.class);
190 
191         assertSame(collaborator, collaboratorBean);
192     }
193 
194     @Test
195     void lookUpBeanByTypeTwiceHavingSingleInjectableInstance(@Injectable Collaborator collaborator) {
196         BeanFactory beanFactory = new /* TestWebApplicationContext(); */DefaultListableBeanFactory();
197 
198         Collaborator collaboratorBean1 = beanFactory.getBean(Collaborator.class);
199         Collaborator collaboratorBean2 = beanFactory.getBean(Collaborator.class);
200 
201         assertSame(collaborator, collaboratorBean1);
202         assertSame(collaborator, collaboratorBean2);
203     }
204 
205     static class Level1 {
206         @Autowired
207         Level2 level2;
208     }
209 
210     static class Level2 {
211         @Autowired
212         Level3 level3;
213     }
214 
215     static class Level3 {
216         Level3(@SuppressWarnings("unused") String str) {
217         }
218     }
219 
220     @Test
221     public void lookupBeanWithDependencyOnAnotherWhichAlsoDependsOnAnotherWhichHasAOneArgumentConstructor() {
222         Throwable throwable = assertThrows(IllegalStateException.class, () -> {
223             BeanFactory beanFactory = new TestWebApplicationContext();
224             Level1 level1 = beanFactory.getBean(Level1.class);
225 
226             assertNotNull(level1);
227             assertNotNull(level1.level2);
228             assertNotNull(level1.level2.level3);
229         });
230         assertEquals("Missing @Tested or @Injectable for parameter \"str\" in constructor Level3(String str)" + "\r\n"
231                 + "  when initializing field \"Level3 level3\"" + "\r\n" + "  when initializing field \"Level2 level2\""
232                 + "\r\n" + "  of @Tested object \"Level1 level1\"", throwable.getMessage());
233     }
234 
235     @Test
236     void failToLookupBeanButCatchExceptionAndThrowAnother_stillShouldIncludedFilteredStackTrace() {
237         BeanFactory beanFactory = new TestWebApplicationContext();
238 
239         try {
240             beanFactory.getBean(Level1.class);
241         } catch (IllegalStateException e) {
242             for (StackTraceElement ste : e.getStackTrace()) {
243                 assertFalse(ste.getClassName().startsWith("mockit.internal."), ste.toString());
244             }
245         }
246     }
247 }