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

Spock单元测试StepVerifier.expectError传任意类型均通过问题

问题根因

两个核心问题导致测试断言完全未生效,出现任意类型参数都能通过的假阳性结果:

  • 最核心的错误:StepVerifier的断言链没有调用终止方法verify()。
    StepVerifier的执行逻辑是:所有expectXxx方法只是在组装校验规则,不会触发任何实际的订阅和校验动作,只有调用最终的verify()(或者verifyTimeout、verifyThenAssertThat这类终止方法)时,才会真正订阅被测的Mono/Flux,按顺序执行所有预设的断言。你现在只写了.expectError(String.class)就终止了代码,等于只是创建了一个StepVerifier实例,没有跑任何校验,这就是你遇到任意类型入参(哪怕是String.class)都能通过测试的直接原因。
  • Spock测试代码存在顺序错误与潜在逻辑缺陷:
    1. given块变量初始化顺序颠倒:你先执行new PaymentsBO(contractServiceMock),之后才初始化contractServiceMock = Mock(ContractClient),构造被测类时传入的mock实际是null,后续调用会直接触发空指针;
    2. 被测业务代码存在NPE风险:onErrorResume逻辑中直接调用throwable.getCause(),如果抛出的异常实例没有设置cause(比如你测试中构造的无参new ContractServiceException()),这里会直接抛出NullPointerException,最终返回的错误信号是NPE,不是你预期的CustomException。
修正方案

首先调整单元测试代码,修复初始化顺序问题,补充verify()调用:

def "Returns an error if the Contract Service returns a non-200"() {
    given:
    // 先初始化Mock对象,再注入到被测类
    def contractServiceMock = Mock(ContractClient)
    def testSubject = new PaymentsBO(contractServiceMock)
    
    when:
    def result = testSubject.updatePaymentInfo(record)

    then:
    // Mock交互校验放在then块,Spock会自动在when执行前完成桩注入
    1 * contractServiceMock.getContract(CONTRACT_UUID) >> Mono.error(new ContractServiceException())
    // StepVerifier必须调用verify()触发校验,传入预期的异常类型
    StepVerifier.create(result)
        .expectError(CustomException.class)
        .verify()
}

其次修复业务代码中的空指针风险,调整异常拼接逻辑:

@Service
@RequiredArgsConstructor
public class PaymentsBO {
    private final ContractClient contractClient;

    public Mono<Void> updatePaymentInfo(Request record) {
        return contractClient
                .getContract(UUID.fromString(record.getContractUuid()))
                .onErrorResume(throwable -> Mono.error(() -> new CustomException(
                        "Contract Service responded with a non-200 due to "
                                + Optional.ofNullable(throwable.getCause()).orElse(throwable).getMessage())))
                .flatMap(
                    // happy-path logic
                );
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 05:24:52