You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:50:08