SpringBoot 3.x中Mockito构造注入测试异常问题排查
构造注入下Mockito测试类批量执行失败的问题分析
问题场景
基于SpringBoot 3.x开发,MyService采用构造注入方式依赖三个组件:
@Service class MyService { private final DependencyOne one; private final DependencyTwo two; private final DependencyThree three; @Autowired public MyService(DependencyOne one, DependencyTwo two, DependencyThree three) { this.one = one; this.two = two; this.three = three; } // 业务方法... }
对应的Mockito测试代码如下:
@ExtendWith(MockitoExtension.class) class MyServiceTest { @Mock private DependencyOne one; @Mock private DependencyTwo two; @Mock private DependencyThree three; @InjectMocks private MyService tested; @Test void testA() { // 测试逻辑... } @Test void testB() { // 测试逻辑... } }
出现的异常现象:
- 执行
mvn test -Dtest="MyServiceTest"运行整个测试类时,testB失败; - 单独执行
mvn test -Dtest="MyServiceTest#testB"时,testB成功; - 若将
MyService改为字段注入方式,所有测试均能通过:
@Service class MyService { @Autowired private DependencyOne one; @Autowired private DependencyTwo two; @Autowired private DependencyThree three; // 业务方法... }
问题原因
这是Mockito的@InjectMocks在构造注入场景下的默认行为导致的:
- 构造注入时,
@InjectMocks会通过构造函数创建MyService实例,默认仅在测试类初始化时执行一次,整个测试类的所有测试方法共享同一个实例; - 如果
testA中对mock对象做了存根(Stub)、验证或者状态修改,这些状态会被保留到testB中,导致testB的执行环境不是干净的,从而引发失败; - 字段注入时,
@InjectMocks通过反射设置字段值,默认会在每个测试方法执行前重新注入,每个测试都拥有独立的mock状态和MyService实例,因此不会出现测试间的状态污染。
解决方法
方法一:手动在每个测试前初始化实例
放弃依赖@InjectMocks的自动注入,改用@BeforeEach在每个测试方法前手动创建MyService实例,确保每个测试都拿到全新的对象:
@ExtendWith(MockitoExtension.class) class MyServiceTest { @Mock private DependencyOne one; @Mock private DependencyTwo two; @Mock private DependencyThree three; private MyService tested; @BeforeEach void setUp() { tested = new MyService(one, two, three); // 可选:如果需要彻底重置mock状态,添加以下代码 // Mockito.reset(one, two, three); } @Test void testA() {...} @Test void testB() {...} }
方法二:配置Mockito每次测试前重新注入
使用@MockitoSettings注解(Mockito 4.5+版本支持,SpringBoot 3.x配套的Mockito版本满足要求),强制@InjectMocks在每个测试方法前重新创建并注入实例:
@ExtendWith(MockitoExtension.class) @MockitoSettings(reinjectMocks = ReinjectMocksMode.BEFORE_EACH_TEST_METHOD) class MyServiceTest { @Mock private DependencyOne one; @Mock private DependencyTwo two; @Mock private DependencyThree three; @InjectMocks private MyService tested; @Test void testA() {...} @Test void testB() {...} }
内容的提问来源于stack exchange,提问作者JiKra
相关产品推荐
相关产品推荐

