Spring测试中@MockBean在目标Bean构造函数内Stub不生效该如何解决
问题根因
Spring上下文初始化阶段会完成所有Bean的实例化和依赖注入,MyBeanToTest的构造函数会在测试方法执行之前就被调用,你写在testSomething()里的Stub规则此时还没有执行,所以jmsTemplate.getConnectionFactory()默认返回null,触发空指针。
解决方案
有三种常用的调整方式可以解决这个问题:
方案1:提前在@BeforeAll阶段配置Stub(需配合静态Mock)
将JmsTemplate的Mock也改为静态,在所有Bean实例化前完成Stub配置:
@SpringBootTest public class MyTestClass { @Autowired MyBeanToTest myBeanToTest; // 改为静态MockBean,上下文初始化时就会用这个静态实例 @MockBean private static JmsTemplate jmsTemplate; @Mock private static ConnectionFactory connectionFactory; // 在Spring上下文初始化前执行Stub配置 @BeforeAll static void initStub() throws JMSException { when(jmsTemplate.getConnectionFactory()).thenReturn(connectionFactory); // 连带Stub后续的createSession调用,避免二次空指针 when(connectionFactory.createSession()).thenReturn(yourExpectedSessionMock); } @Test public void testSomething() { // 直接写测试逻辑即可 ... } }
方案2:用@TestConfiguration提前配置带Stub规则的Mock
自定义测试配置类,在Bean实例化前就创建好带Stub的Mock对象:
@SpringBootTest public class MyTestClass { @TestConfiguration static class TestMockConfig { @Bean public JmsTemplate jmsTemplate() throws JMSException { JmsTemplate mockJmsTemplate = Mockito.mock(JmsTemplate.class); ConnectionFactory mockCf = Mockito.mock(ConnectionFactory.class); when(mockJmsTemplate.getConnectionFactory()).thenReturn(mockCf); when(mockCf.createSession()).thenReturn(Mockito.mock(Session.class)); return mockJmsTemplate; } } @Autowired MyBeanToTest myBeanToTest; @Test public void testSomething() { ... } }
方案3(设计层面优化,更推荐):避免在构造函数中执行依赖的调用逻辑
将构造函数中的初始化逻辑迁移到@PostConstruct方法,或者懒加载ConnectionFactory,这样可以更灵活的控制Stub时机,也符合Spring Bean的生命周期规范:
@Autowired public MyBeanToTest(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } @PostConstruct public void init() throws JMSException { this.cf = this.jmsTemplate.getConnectionFactory(); cf.createSession(); }
内容的提问来源于stack exchange,提问作者Endre Gabriel
相关产品推荐
相关产品推荐

