类成员变量调用ApplicationContext.getBean加载Bean时如何编写Junit测试
问题根因
类级别的成员变量会在类加载阶段完成初始化,你写的Beanx beanx = ApplicationContext.getBean("beanName")会在类加载时直接触发Spring容器的Bean查询,而Junit测试默认会先加载业务类,再初始化Spring上下文,此时ApplicationContext实例还未赋值,自然触发空指针异常。
可行解决方案
方案1:调整Bean注入方式,避免硬编码获取Bean
这是最优解,从根源上避免硬编码依赖容器的问题:
- 改用Spring原生依赖注入替代
ApplicationContext.getBean()硬编码调用,把Beanx声明为类的普通成员变量,加@Autowired/@Resource注解注入即可 - 业务代码优化示例:
// 原错误写法 // public class YourService { // private Beanx beanx = ApplicationContext.getBean("beanName"); // } // 优化后写法 @Component public class YourService { @Autowired private Beanx beanx; }
- 测试类直接用Spring测试注解即可自动完成依赖注入:
@SpringBootTest public class YourServiceTest { @Autowired private YourService yourService; @Test public void testBizLogic() { // 编写测试逻辑即可 } }
方案2:无法修改业务代码时,Mock静态方法返回
如果原有业务逻辑不允许调整,用Mock工具模拟ApplicationContext.getBean()的返回,跳过真实调用:
- 引入Mockito 4.0+版本(支持静态方法Mock),测试类写法如下:
@ExtendWith(MockitoExtension.class) public class YourServiceTest { @Mock private Beanx mockBeanx; // 如果是静态类变量,需要把Mock逻辑放在@BeforeAll中,保证Mock在业务类加载前执行 @BeforeEach public void initMock() { MockedStatic<ApplicationContext> mockedContext = Mockito.mockStatic(ApplicationContext.class); mockedContext.when(() -> ApplicationContext.getBean("beanName")).thenReturn(mockBeanx); // 上下文Mock完成后再实例化业务类 YourService yourService = new YourService(); } @Test public void testBizLogic() { // 提前Mock Beanx对应方法的返回值 when(mockBeanx.bizMethod(any())).thenReturn("模拟返回结果"); // 执行测试逻辑 } }
方案3:需要用真实Bean测试时,调整加载顺序
如果测试需要依赖真实的Beanx实例,调整测试类的初始化顺序,先完成Spring上下文加载再实例化业务类:
@SpringBootTest public class YourServiceTest { private YourService yourService; // 注入已经初始化完成的Spring上下文 @BeforeEach public void init(ApplicationContext context) { // 上下文准备完成后再实例化业务类,此时getBean可以正常拿到实例 yourService = new YourService(); } @Test public void testBizLogic() { // 编写测试逻辑即可 } }
内容的提问来源于stack exchange,提问作者anurag1007
相关产品推荐
相关产品推荐

