如何在@SpringBootTest中Mock@PostConstruct依赖的Bean
问题解决方案
问题根源分析
- 直接使用
@MockBean C时,@BeforeEach是在Spring上下文初始化完成(包括A的@PostConstruct执行)后才执行的,导致A的postConstruct调用c.getString()时,Mock的C还未设置返回值,默认返回null触发空指针异常。 - 之前的
@TestConfiguration方案因@AutoConfigureBefore注解干扰了Bean加载顺序,导致Spring无法找到A的Bean。
方案一:通过@TestConfiguration提前创建并配置Mock的C
在测试类内部定义测试配置类,提前创建Mock的C并设置好返回值,确保Spring上下文初始化时,依赖链中的B和A能注入正确的Mock实例。
@SpringBootTest class DemoApplicationTests { @Autowired A a; @TestConfiguration static class TestConfig { @Bean public C c() { C mockC = Mockito.mock(C.class); // 提前设置Mock行为,确保@PostConstruct调用时生效 when(mockC.getString()).thenReturn("C_mocked"); return mockC; } } @Test void canLoadContext() { assertThat(a).isNotNull(); // 可以验证@PostConstruct的执行结果 assertThat(a.s).isEqualTo("C_MOCKED"); } }
方案二:Mock B类,控制其返回的C实例
如果不想直接Mock C,也可以Mock B类,让它的get()方法返回预先配置好的Mock C,从依赖链上游解决问题。
@SpringBootTest class DemoApplicationTests { @MockBean B b; @Autowired A a; @BeforeAll static void setupMock() { C mockC = Mockito.mock(C.class); when(mockC.getString()).thenReturn("C_mocked"); // 让Mock的B返回配置好的Mock C when(b.get()).thenReturn(mockC); } @Test void canLoadContext() { assertThat(a).isNotNull(); assertThat(a.s).isEqualTo("C_MOCKED"); } }
方案三:提前初始化Mock行为(针对@MockBean的修正)
如果坚持使用@MockBean,需要在Spring上下文初始化前设置Mock的返回值,改用@BeforeAll静态方法完成配置:
@SpringBootTest class DemoApplicationTests { @MockBean C c; @Autowired A a; @BeforeAll static void setupMock(@Autowired C mockC) { // 在上下文初始化前设置Mock行为 when(mockC.getString()).thenReturn("C_mocked"); } @Test void canLoadContext() { assertThat(a).isNotNull(); assertThat(a.s).isEqualTo("C_MOCKED"); } }
内容的提问来源于stack exchange,提问作者Gabriel Carrera
相关产品推荐
相关产品推荐

