Jacoco与SonarQube在Gradle多工程中的应用

Scenario

有如下工程结构:

rootProject
|
├── subProject1
|   |
|   └── build.gradle
|
├── subproject2
|   |
|   └── build.gradle
|
└── build.gradle

rootProject/build.gradle里引入并使用sonarqube plugin (sonarqube plugin本身具有多工程分析的能力,因此只需在主工程中引入):

plugins {
    id "org.sonarqube" version "2.7"
}

如果test case用了TestNG,请指明

test {
    useTestNG()
}

Jacoco会根据test的配置,自动去寻找运行test后所生成的 *.exec文件,用于类型为JacocoReport(如jacocoTestReport)的task生成相应的测试报告。

关于 jacoco 插件的使用,请参考 https://docs.gradle.org/current/userguide/jacoco_plugin.html, 引入 java 插件的目的是让相应的 project自动生成 jacocoTestReport task, 而 jacocoTestReport task 的主要作用就是用来生成覆盖率测试报告,以及生成用于 sonarqube 分析的 XML 文件

现在要将整个工程的测试报告上传到SonarQube,有以下两种方法。

Solutions

方法一

合并所有工程生成的*.exec文件,jacocoTestReport利用合并后的文件来生成sonar所需的xml文件,因此合并的代码应该放置在rootProject的build.gradle里,具体代码如下:

// Merge jacoco coverage results and generate reports in xml and html format
jacocoTestReport {
    sourceDirectories = files()
    classDirectories = files()
    executionData = files()

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

    // Work-around to allow us to build list of executionData files in doFirst
    onlyIf = {
        true
    }

    /*
     * Builds list of source dirs, class dirs, and executionData files
     * when task is run, not at script evaluation time
     */
    doFirst {
        subprojects.findAll {
            it.pluginManager.hasPlugin('jacoco')
        }.each { subproject ->
            additionalSourceDirs files((Set) subproject.sourceSets.main.allJava.srcDirs)
            additionalClassDirs ((FileCollection) subproject.sourceSets.main.output)
            executionData subproject.tasks.jacocoTestReport.executionData
        }

        executionData = files(executionData.findAll {
            it.exists()
        })
    }
}

上述task会在rootProject里生成build目录,而build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml正是sonarqube分析覆盖率时所需要的,因此在rootProject里配置

// Configure sonar to take the merged xml rseult
sonarqube {
    properties {
        property "sonar.coverage.jacoco.xmlReportPaths", jacocoTestReport.reports.xml.destination
    }
}
tasks['sonarqube'].dependsOn(jacocoTestReport)

即可。

方法二

利用sonarqube插件可以自动分析主工程与子工程的特性,每个工程的sonarqube都指定sonar.coverage.jacoco.xmlReportPaths, 最终会汇总在SonarQube server上。具体步骤如下:

  • 在所有工程里都引入和使用jacoco与java插件,或者在rootProject里使用如下代码:

    allprojects {
        apply plugin: 'java'
        apply plugin: 'jacoco'
    }
    

    目的是让所有工程都有jacocoTestReport task。

  • 每个工程都将jacocoTestReport的xml功能打开:

      jacocoTestReport {
          reports {
              html.enabled = true
              xml.enabled = true
              csv.enabled = false
          }
      }
    
  • 然后在每个工程里加上

    sonarqube {
        properties {
            property "sonar.coverage.jacoco.xmlReportPaths", jacocoTestReport.reports.xml.destination
        }
    }
    

关于如何排除需要分析的文件

如果你最终的测试报告就是jacocoTestReport生成的,则可以通过

jacocoTestReport {
    afterEvaluate {
        classDirectories = files(classDirectories.files.collect {
            fileTree(dir: it, exclude: 'com/blah/**')
        })
    }
}

来排除不必要的文件,可以参考 https://stackoverflow.com/questions/29887805/filter-jacoco-coverage-reports-with-gradle

但如果你的测试报告最终是由SonqrQube来分析的,那么需要配置sonar.exclusions来排除,例如

sonarqube {
    properties {
        property "sonar.exclusions", [
                '**/com/siemens/mindsphere/actuator/**/*',
                '**/com/siemens/mindsphere/config/*Config.java'
        ]
    }
}

对于每个子工程想要排除文件,请将上述配置加到相应的子工程的build.gradle中,rootProject的排除配置只对rootProject有效,不会影响到其他subProject, 即sonarqube的排除配置只对其所属的工程有效。

注意,jacoco排除的文件并不会影响sonarqube的分析结果,尽管sonarqube使用了jacocoTestReport生成的xml文件进行分析,但是sonarqube分析的整个范围是由sonar.sources(默认值为${sourceSets.main.allSource.srcDirs})决定的,请参考https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/。简单说来,jacoco与sonar都有自己的“分析集”,jacocoTestReport排除的文件并没有影响到sonar的“分析集”大小。

代码覆盖信息是由test所生成的*.exec文件决定的,jacocoTestReport可以直接利用*.exec进行分析,而sonarqube需要利用jacocoTestReport基于*.exec所生成的xml文件来进行分析,即它们所拥有的代码覆盖信息本质上是一样的,因此jacoco与sonarqube的文件排除,只会改变相应的“分析集”大小,不会互相影响相应的分析。

你可能感兴趣的:(Jacoco与SonarQube在Gradle多工程中的应用)