踩坑日记之Gradle自定义JacocoReport跟Test task

本文记录了在Gradle中配置Jacoco单元测试覆盖率报告时遇到的问题,包括自定义test任务为何被SKIPPED,如何使用onlyIf条件,以及解决test.exec文件不存在和默认包含的问题。通过分析源码和调整配置,实现了预期的测试报告目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起因

最近新写了一个项目,为了更好的保证项目输出的质量,引入了单元测试覆盖率统计框架Jacoco。由于gradle官网上的案例只有几个默认的task(test、JacocoTestReport等)的设置,而我希望能够额外为不同的层提供单独的test,也就发生了接下来这些有趣的事儿。

1. 为什么JacocoTestReport总是被SKIPPED

首先,我写了一个自定义的test。并且通过将finalizedBy指定为JacocoTestReport来让test执行完毕后自动执行JacocoTestReport。自定义test以及JacocoTestReport 如下:

//自定义test
task serviceTest(type: Test) {
   
   
    useTestNG()
    useJUnitPlatform()

	finalizedBy jacocoTestReport

    jacoco {
   
   
        enabled = true
        //指定原始数据文件位置
        destinationFile = layout.buildDirectory.file("jacoco/${taskName}.exec").get().asFile
        includes = ['xxxservice']
        excludeClassLoaders = []
        includeNoLocationClasses = false
        sessionId = "<auto-generated value>"
        output = JacocoTaskExtension.Output.FILE
    }
}

jacocoTestReport {
   
   
    // tests are required to run before generating the report
    dependsOn serviceTest
		
	//指定覆盖率统计数据文件。
	executionData(layout.buildDirectory.file("jacoco/${serviceTest.name}.exec").get().asFile)

    afterEvaluate {
   
   
        classDirectories.setFrom(files(classDirectories.files.collect {
   
   
            fileTree(dir: it, include: ['xxxservice'])
        }))
    }
    reports {
   
   
        xml.required = false
        csv.required = false
        html.outputLocation = layout.buildDirectory.dir('jacocoReport')
    }
}

看起来似乎没啥问题,该做的都做了。但是执行的时候程序却跳过了jacocoTestReport。当时特别纳闷,就去网上提了个问题。最后gradle官方的工作人员给了答复,大概意思是executionData对应的文件不存在,在jacocoTestReport里加上onlyIf = {true} 可以保证jacocoTestReport会执行,并且执行最终会报出test.exec文件不存在的错误。ok,有方向了,那就一个一个来分析。

2. task里的onlyIf

事实上,onlyIf决定了task是否被执行。同时,onlyIf可以设置多个规则判断,如果所有的规则判断都返回为true,才会执行task。否则,跳过task

2.1 SkipOnlyIfTaskExecuter

让我们进入SkipOnlyIfTaskExecuter一探究竟:

public class SkipOnlyIfTaskExecuter implements TaskExecuter {
   
   
	@Override
    public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
   
   
        boolean skip = !task.getOnlyIf().isSatisfiedBy(task);
				
		//跳过task
        if (skip) {
   
   
            return TaskExecuterResult.WITHOUT_OUTPUTS;
        }
				
		//执行task
        return executer.execute(task, state, context);
    }

	//遍历所有规则
	public boolean isSatisfiedBy(T object) {
   
   
        Spec<? super T>[] specs = getSpecsArray();
        for (Spec<? super T> spec : specs) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值