使用jacoco和gradle多模块项目进行跨模块代码覆盖

时间:2017-01-02 15:58:03

标签: gradle sonarqube jacoco multi-module

我们使用gradle 3.3和jacoco工具Verson 0.7.6.201602180812。 我们有一个这样的gradle多项目:

    • PROD1
    • Prod2的
    • prod3
    • INT-测试

我们使用单元测试对所有生成test.exec文件的子项目测试项目源和jacoco。我们在int-test项目中有额外的集成测试,将jacoco结果添加到int-test项目中的test-exec。我们在父项目中使用sonarqube gradle插件(2.2.1)来收集SonarQube服务器v6.2的所有内容。

一切都运行正常,测试在他们自己的项目中测试源:代码覆盖率在jacoco报告和SonarQube上测量。

只有在测试项目的覆盖率报告中或在带有类的项目中,才会测量prod项目(单个过程)中的源的集成测试(int-test项目)覆盖。

可能需要以某种方式将顶层项目的覆盖数据结合起来 - 有谁知道如何做到这一点?最好的SonarQube仍然可以显示单个模块级别的覆盖范围。

修改 这是一个小型测试项目:https://github.com/MichaelZett/coveragetest 运行“build smokeTest sonarqube”会导致:

  • 运行所有测试
  • 在所有子项目中生成jacoco / test.exec和test-results / test / ...文件
  • 在sonarqube解析这些内容
  • 正确测量在自己的项目中测试源的测试的覆盖范围
  • 缺少测试另一个项目中的源的测试的覆盖范围

3 个答案:

答案 0 :(得分:5)

如评论中所述,您必须先获取merge the Jacoco execution数据,然后告诉sonarqube使用该数据而不是每个子模块生成的单个exec文件。

我在这里添加一个例子,因为接受的答案中提供的链接有点误导。他们中的大多数为您提供了不同的解决方法来合并Jacoco报告,而不是合并执行数据,这就是您想要的。

以下是它的样子:

def allTestCoverageFile = "$buildDir/jacoco/allTestCoverage.exec"

sonarqube {
    properties {
        property "sonar.projectKey", "your.org:YourProject"
        property "sonar.projectName", "YourProject"
        property "sonar.jacoco.reportPaths", allTestCoverageFile
    }
}

task jacocoMergeTest(type: JacocoMerge) {
    destinationFile = file(allTestCoverageFile)
    executionData = project.fileTree(dir: '.', include:'**/build/jacoco/test.exec')
}

task jacocoMerge(dependsOn: ['jacocoMergeTest']) {
    // used to run the other merge tasks
}

subprojects {
    sonarqube {
        properties {
            property "sonar.jacoco.reportPaths", allTestCoverageFile
        }
    }
}

简而言之:

  • 首先,我们为测试报告(allTestCoverageFile)定义全局覆盖文件输出。
  • 然后我们需要告诉Sonarqube使用该文件(使用sonar.jacoco.reportPaths)。但请注意,我们还必须在子项目关闭中执行此操作。这非常重要。不要错过。
  • 最后,我们创建了一个自定义任务,该任务从JacocoMerge(来自Jacoco插件的孵化类)扩展,将所有项目(executionData)的所有测试覆盖率报告合并到我们的{{1 }}。
  

如果您使用的是6.2之前的SonarQube版本,请使用sonar.jacoco.reportPath属性

答案 1 :(得分:2)

说到SonarQube:您可以在所有模块中使用jacoco.exec的相同位置来获取汇总报告。确保在构建之前删除该文件并将其附加到所有模块中。

仅谈Gradle:看看

答案 2 :(得分:0)

subprojects {
    apply(plugin: 'org.jetbrains.kotlin.jvm')

    repositories {
        jcenter()
        mavenCentral()
   }
}

task codeCoverageReport(type: JacocoReport) {

    // Gather execution data from all subprojects
    executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")

    // Add all relevant sourcesets from the subprojects
    subprojects.each {
        sourceSets it.sourceSets.main
    }

    reports {
        xml.enabled true
        html.enabled true
        csv.enabled false
    }
}

// always run the tests before generating the report
codeCoverageReport.dependsOn {
    subprojects*.test
}

sonarqube {
    properties {
        property "sonar.projectKey", "your_project_key"
        property "sonar.verbose", true
        property "sonar.projectName", "Your project name"
        property "sonar.coverage.jacoco.xmlReportPaths", "${rootDir}/build/reports/jacoco/codeCoverageReport/codeCoverageReport.xml"
    }
}

运行覆盖测试的命令:

./gradlew codeCoverageReport
./gradlew sonarqube -x test (test is excluded since already run and sonarqube by default executes test)

需要注意的两点使其起作用:

  1. 要提供所有模块的可用资源集,请遍历子项目并累积可用的资源集。 subprojects.sourceSets.main.allSource.srcDirs 无法正常工作。
  2. sonar.jacoco.reportPaths 已被弃用。我们需要使用 sonar.coverage.jacoco.xmlReportPaths 。在此处查看文档