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

从mockito-all迁移至mockito-core后测试失败,如何修复?

Mockito从1.9.5迁移到2.28.2后测试失效的解决方法

问题背景

项目从mockito-all:1.9.5升级到mockito-core:2.28.2后,部分原有测试执行失败。以下是典型案例:

测试代码

@ExtendWith(CdiUnitExtension.class)
@AdditionalClasses({
    XmlMockUnmarshaller.class
})
public class FeaturesTest {

    @Produces
    @Mock
    private RefService refService;
    
    @Produces
    @Mock
    private PaymentService paymentService;
    
    private CacheData cacheData;
    
    @BeforeEach
    public void setUp() {
        this.cacheData = new CacheData();
        this.cacheData.setDateExecution("12/12/2015");
        when(refService.isDateAvailable(anyString())).thenReturn(true);
    }
    
    @Test
    public void shouldReturnErrorIfReasonHasInvalidChars() {
        // Given
        this.cacheData.setReason("qhsdlq$98%èd");
    
        // When
        List<Error> errors = paymentService.validatePayment(this.cacheData);
    
        // Then
        assertTrue(errors.size() == 1); // 测试失败:errors.size() = 2
        assertEquals(errors.get(0).getField(), "reason");
    }
}

对应的业务方法

@Inject
RefService refService;
...
public List<Error> validatePayment(CacheData cacheData) {
    ...
    if (!refService.isDateAvailable(cacheData.getExecutionDate())) {
        errors.add(new Error("executionDate"));
    }
    ...
    return errors;
}

问题现象

测试执行后错误列表包含2个错误,setUp中配置的refService.isDateAvailable()返回true的Mock逻辑完全没生效,导致多了一个executionDate字段的错误。


解决方法

方案1:改用Mockito原生扩展(推荐)

放弃CDIUnitExtension,直接使用MockitoExtension来管理Mock和依赖注入,避免CDI上下文导致的实例不一致问题:

@ExtendWith(MockitoExtension.class)
public class FeaturesTest {

    @Mock
    private RefService refService;
    
    @InjectMocks
    private PaymentService paymentService;
    
    private CacheData cacheData;
    
    @BeforeEach
    public void setUp() {
        this.cacheData = new CacheData();
        this.cacheData.setDateExecution("12/12/2015");
        when(refService.isDateAvailable(anyString())).thenReturn(true);
    }
    
    @Test
    public void shouldReturnErrorIfReasonHasInvalidChars() {
        this.cacheData.setReason("qhsdlq$98%èd");
        
        List<Error> errors = paymentService.validatePayment(this.cacheData);
        
        assertTrue(errors.size() == 1);
        assertEquals(errors.get(0).getField(), "reason");
    }
}

方案2:保留CDIUnit并修正Mock实例一致性

如果必须依赖CDIUnitExtension,需要确保测试类中配置的Mock实例和CDI注入到PaymentService中的是同一个:

@ExtendWith(CdiUnitExtension.class)
@AdditionalClasses({
    XmlMockUnmarshaller.class
})
public class FeaturesTest {

    @Inject
    private PaymentService paymentService; // 直接从CDI上下文注入
    
    @Produces
    @Mock
    private RefService refService;
    
    private CacheData cacheData;
    
    @BeforeEach
    public void setUp() {
        this.cacheData = new CacheData();
        this.cacheData.setDateExecution("12/12/2015");
        // 显式初始化Mock,确保实例被CDI上下文正确识别
        MockitoAnnotations.openMocks(this);
        when(refService.isDateAvailable(anyString())).thenReturn(true);
    }
    
    @Test
    public void shouldReturnErrorIfReasonHasInvalidChars() {
        this.cacheData.setReason("qhsdlq$98%èd");
        
        List<Error> errors = paymentService.validatePayment(this.cacheData);
        
        assertTrue(errors.size() == 1);
        assertEquals(errors.get(0).getField(), "reason");
    }
}

原因分析

Mockito 2.x对@Mock注解的处理逻辑与1.x存在差异:在CDI环境下,@Produces生成的Mock实例,和测试类中直接持有的refService实例可能不是同一个对象。测试代码中配置的Mock行为只作用于测试类的实例,但PaymentService注入的是CDI上下文生成的另一个未配置的Mock(默认返回false),因此触发了executionDate的错误校验。

内容的提问来源于stack exchange,提问作者l0r3nz4cc10

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:40:45