Spring Boot 2.5中如何Mock Service Bean内部依赖的另一Service方法
核心问题原因
@PostConstruct是Spring Bean初始化阶段的回调方法,执行时机远早于测试方法的运行时机。你之前的配置不生效,本质是Mock方法的打桩时机晚于A的@PostConstruct执行时机,等到你在测试方法中给B的方法打桩时,A的初始化逻辑已经跑完,调用的是B的原始方法。
可用解决方案
方案1:保留Spring上下文测试,提前定义Mock行为
如果你需要依赖Spring容器的完整能力,可以通过@TestConfiguration提前初始化打桩完成的Mock Bean,替换容器中的原始B实例,确保A初始化时拿到的就是已经打桩好的B:
@SpringBootTest class TestClass { @Autowired private A a; // 注入容器中的Mock B实例,用于后续验证 @Autowired private B b; @TestConfiguration static class MockBConfig { @Bean @Primary public B mockedB() { B mockB = Mockito.mock(B.class); // 提前对目标方法打桩 Mockito.doNothing().when(mockB).methodToBeMocked(); // 若方法有返回值,写法为 Mockito.when(mockB.xxx()).thenReturn(自定义返回值); return mockB; } } @Test void mytest() { a.anyMethod(); // 可验证@PostConstruct中的方法调用符合预期 Mockito.verify(b, Mockito.times(1)).methodToBeMocked(); } }
方案2:纯Mockito单元测试(无Spring上下文,性能更高)
如果不需要Spring容器的其他能力,直接用Mockito完成依赖注入和初始化,完全可控执行顺序:
@ExtendWith(MockitoExtension.class) class TestClass { // 自动实例化A,将下方的Mock B注入到A中 @InjectMocks private A a; @Mock private B b; @BeforeEach void init() { // 先对B的方法打桩 Mockito.doNothing().when(b).methodToBeMocked(); // 手动触发A的@PostConstruct逻辑 a.postconstruct(); } @Test void mytest() { a.anyMethod(); Mockito.verify(b, Mockito.times(1)).methodToBeMocked(); } }
注意事项
- 不要把Mock方法的打桩逻辑写在@Test测试方法内部,此时A的@PostConstruct已经执行完成,打桩不会生效
- 注意方法名、参数的拼写完全匹配,否则Mockito会匹配不到目标方法,打桩失效
- 如果使用@MockBean注解,打桩逻辑需要写在@BeforeEach方法中,才能赶在Spring上下文初始化前生效
内容的提问来源于stack exchange,提问作者icordoba
相关产品推荐
相关产品推荐

