Quarkus Mockito下责任链模式ValidatorChain设置失效问题求助
问题解决:Quarkus Mockito环境下责任链模式验证逻辑无法执行
问题场景
在Quarkus服务中通过CDI Bean实现了基于责任链的验证逻辑,但在使用Mockito进行测试时,调用ValidatorChain.setFirstValidator()后,firstValidator始终为null,导致验证逻辑未执行,代码覆盖率缺失。
问题根源
测试代码存在以下几个关键问题:
- 混用
@InjectMocks与手动Mockito.mock()创建实例,导致CDI注入的Mock对象与测试中操作的实例不一致 - 手动调用
MockitoAnnotations.openMocks(this),与Quarkus Test的自动Mock初始化机制冲突 - 在
setUp()中重新赋值Mock对象(va = Mockito.mock(ValidatorA.class)),覆盖了@Mock注解创建的实例,导致服务类中注入的Mock与测试代码中的实例不匹配 - 错误地将
ServiceImpl手动Mock后再用@InjectMocks,破坏了CDI的注入逻辑
解决方案
1. 修正测试类的Mock注解使用
使用Quarkus Mockito提供的注解正确管理Mock实例,避免手动创建和赋值:
- 用
@Mock标注所有需要Mock的Validator和ValidatorChain - 用
@InjectMocks标注待测试的ServiceImpl,让Mockito自动将Mock注入到服务类中 - 移除手动调用
MockitoAnnotations.openMocks(this),QuarkusTest会自动完成Mock初始化
2. 确保Mock实例一致性
不要在setUp()中重新赋值Mock对象,直接使用@Mock创建的实例进行操作。
3. 正确触发真实方法执行
在测试中,对applyRaf方法设置thenCallRealMethod()时,确保服务类中的依赖都已正确注入。
修正后的测试代码
import org.mockito.InjectMocks; import org.mockito.Mock; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; @QuarkusTest class CodeTest { @Nested class ApplyUpdateCases { @Mock ValidatorA va; @Mock ValidatorB vb; @Mock ValidatorC vc; @Mock ValidatorChain validatorChain; @InjectMocks ServiceImpl rafservice; // 直接注入ServiceImpl,而非手动Mock @BeforeEach void setUp() { // 初始化责任链关系 va.setNextValidator(vb); vb.setNextValidator(vc); } @Test public void testValidateSelfRAF() { // 模拟其他依赖方法的返回值 when(rafservice.createRaf(any())).thenReturn(getTestRaf()); when(rafservice.find(any())).thenReturn(getTestRaf()); var rafCreate = rafservice.createRaf(getTestCreate()); var rafUpdate = getTestUpdate(); rafUpdate.getRf().setCustomerId(rafCreate.getCustomerId()); // 让applyRaf执行真实逻辑 doCallRealMethod().when(rafservice).applyRaf(rafUpdate); // 验证validatorChain的setFirstValidator是否被正确调用 rafservice.applyRaf(rafUpdate); verify(validatorChain).setFirstValidator(va); // 模拟验证失败抛出异常,验证逻辑执行 when(validatorChain.validate(any(CheckME.class))).thenThrow(new RafException()); assertThrows(RafException.class, () -> rafservice.applyRaf(rafUpdate)); } } }
额外优化建议
如果希望责任链的初始化逻辑更符合CDI规范,可以将链条的构建移到ServiceImpl的@PostConstruct方法中,避免在业务方法中重复初始化:
@ApplicationScoped public class ServiceImpl implements MyService { @Inject ValidatorChain validatorChain; @Inject ValidatorA va; @Inject ValidatorB vb; @Inject ValidatorC vc; @PostConstruct void initValidatorChain() { va.setNextValidator(vb); vb.setNextValidator(vc); validatorChain.setFirstValidator(va); } public Optional<?> applyRaf(UpdateR updateR) { // 直接使用已初始化的链条进行验证 boolean isValid = validatorChain.validate(buildCheckME(updateR)); if (!isValid) { throw new RafException(); } return Optional.empty(); } private CheckME buildCheckME(UpdateR updateR) { // 构建验证对象的逻辑 return new CheckME(); } }
内容的提问来源于stack exchange,提问作者Qasim
相关产品推荐
相关产品推荐

