Incorrect calculation of coverage in sonarqube 6.2 on Gradle multi module project

I am currently using a multi-module Java project with good coverage and sonarqube 6.2 with the sonarJava 4.10.0.1026 plugin. I am using Gradle 4.0.1, the sonarqube 2.5 plugin and jacoco 0.7.9! Java 8 code.

Due to API-based development, API tests are written as abstract tests in API projects and called from implementation projects that provide constructors for the tests.

When analyzing a project on the sonarqube server, the coverage for implementation projects is measured correctly, but the API projects included in the IMPL project tests have a coverage of 0.0%. The results of these projects are ignored.

Just using the jacoco plugin, I was able to get the same behavior. After doing some research, I found a solution to get the correct reports about yakoko:

task codeCoverageReport(type: JacocoReport) {
  description "Creates a unified JaCoCo test report for the project."

  // Gather execution data from all subprojects
  // (change this if you e.g. want to calculate unit test/integration test coverage separately)
  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
    html.destination file("${buildDir}/reports/jacoco")
    csv.enabled false
  }
}

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

:

JaCoCo:

  1. JaCoCo (codeCoverageReport-Task)
    • 73%
    • 91%
    • 43,1% ( ~ 30% !)
    • 82,1% ( ~ 20% !)

, . , "sonar.jacoco.reportPaths" -parameter, 6.2, , java-analyzer 4.4 sth. . gradle . jacoco.exec .

, .

+4
4

@Lance Java! , . jacoco, . , , , , .

apply plugin: 'base'
apply plugin: 'org.sonarqube'
[...]
allprojects {
  apply plugin: 'java'
  apply plugin: "jacoco"
  [...]
  test {
    [...]
    jacoco {
      append=true
    }
  }
}
[...]
task jacocoMerge( type: JacocoMerge ) {
  dependsOn( subprojects.jacocoTestReport.dependsOn )
  mustRunAfter( subprojects.jacocoTestReport.mustRunAfter )
  destinationFile = file( "${buildDir}/jacoco/mergedTests.exec" )
  executionData = files( subprojects.jacocoTestReport.executionData )
                       .filter { jacocoReportFile -> jacocoReportFile.exists() }
}
tasks.sonarqube.dependsOn jacocoMerge
[...]
sonarqube {
  properties {
    [...]
    property "sonar.jacoco.reportPath", "${buildDir}/jacoco/*.exec"
  }
}

:

, . . Sonar jacoco , :

append=true

. - . jacoco .exec .

:

apply plugin: 'base'
apply plugin: 'org.sonarqube'
[...]
allprojects {
  apply plugin: 'java'
  apply plugin: "jacoco"
  [...]
  test {
    [...]
    jacoco {
      append=true
      destinationFile = file( "${rootProject.buildDir}/jacoco/jacocoTest.exec" ) 
    }
  }
}
[...]
sonarqube {
  properties {
    [...]
    property "sonar.jacoco.reportPath", "${buildDir}/jacoco/*.exec"
  }
}

. :

  • 91.6%
  • 91.7%
  • 91.3%
  • 36
  • 11
  • 433
  • 1,114
  • Unit Test 0
  • Unit Test 0
  • 0
  • Unit Test (%) 100.0%
  • Unit Test 4s

, ...;)

+1

, , additionalSourceDirs additionalClassDirs. :

evaluationDependsOn ':foo' 
task codeCoverageReport(type: JacocoReport) {
    additionalSourceDirs.add project(':foo').sourceSets.main.java.sourceDirectories
    additionalClassDirs.add project(':foo').sourceSets.main.output.classesDirs
    // etc
} 
+1

I'm not sure I understand why this is a problem only for some projects when there is no jacoco and other projects. You can use the Gradle rich API (e.g. TaskCollection and Project ) to find them dynamically.

For instance:

[':project1', ':project3', ':project5'].each {
    project(it) {
        apply plugin: 'java'
        apply plugin: 'jacoco'
    }
}

project(':merger') {
    Collection<Project> jacocoProjects = allprojects.findAll { it.plugins.hasPlugin('jacoco' }
    evaluationDependsOn jacocoProjects 

    task jacocoMerge(type: JacocoMerge) {
        dependsOn jacocoProjects*.tasks.withType(Test)
        executionData jacocoProjects*.tasks.withType(Test)
    }

    task mergedReport(type: JacocoReport) {
        dependsOn jacocoMerge
        executionData jacocoMerge.destinationFile
        sourceDirectories.add(files(jacocoProjects*.sourceSets*.java.srcDirs))
        classDirectories.add(files(jacocoProjects*.sourceSets*.output.classesDir))
    }
}
0
source

Thank you for such kind information.

0
source

Source: https://habr.com/ru/post/1680993/


All Articles