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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:52:35