从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
相关产品推荐
相关产品推荐

