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

Spock模拟CustomException异常致JaCoCo代码覆盖率未覆盖if条件

问题根源

全局GroovyMock靠字节码篡改拦截CustomException的构造过程,这会导致JaCoCo无法正确追踪Validator类中if (environment == null || environment.isEmpty())分支的执行路径——虽然测试能正常跑通(说明分支确实被进入了),但Groovy的Mock机制绕开了JaCoCo插桩的字节码,使得覆盖率报告没把这个分支标记为已覆盖。

解决办法

放弃全局GroovyMock,改用Spock的普通Mock或Spy来模拟CustomException的方法,确保Validator类的原字节码执行路径能被JaCoCo正确捕捉。

具体操作

方式1:用Spy保留原类执行路径(无需修改业务代码)

通过全局Mock仅替换CustomException的构造函数,返回一个Spy实例(Spy会保留原类的字节码逻辑),让JaCoCo能统计到分支执行情况:

class ValidatorSpec extends Specification {
    def "test env check with null environment"() {
        given:
        // 创建Spy实例,保留原类行为
        CustomException ceSpy = Spy(CustomException)
        // 全局Mock构造函数,返回Spy
        GroovyMock(CustomException, global: true)
        new CustomException() >> ceSpy
        // 定义Spy的方法抛出异常
        ceSpy.errorThrowException() >> { throw new IllegalStateException() }

        when:
        new Validator().envCheck(null)

        then:
        thrown(IllegalStateException)
        // 验证方法被调用
        1 * ceSpy.errorThrowException()
    }
}

方式2:改为依赖注入(更推荐,代码更易测试)

调整业务代码,将CustomException通过构造注入的方式传入Validator,测试时直接传入Mock对象,完全避免全局Mock:

修改后的Validator类

public class Validator {
    private final CustomException customException;

    // 构造注入CustomException
    public Validator(CustomException customException) {
        this.customException = customException;
    }

    public void envCheck(String environment) {
        if (environment == null || environment.isEmpty()) {
            customException.errorThrowException();
        }
    }
}

对应的Spock测试代码

class ValidatorSpec extends Specification {
    def "test env check with null environment"() {
        given:
        // 创建普通Mock对象
        CustomException ceMock = Mock(CustomException)
        ceMock.errorThrowException() >> { throw new IllegalStateException() }
        Validator validator = new Validator(ceMock)

        when:
        validator.envCheck(null)

        then:
        thrown(IllegalStateException)
        1 * ceMock.errorThrowException()
    }
}
验证结果

修改后重新运行测试并生成JaCoCo报告,if (environment == null || environment.isEmpty())分支会被标记为已覆盖,同时测试逻辑依然正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 18:22:40