2017-07-07 1 views
3

J'utilise actuellement un projet java multi module java avec une bonne couverture et sonarqube 6.2 avec le plugin sonarJava 4.10.0.1026. J'utilise Gradle 4.0.1, sonarqube plugin 2.5 et jacoco 0.7.9! Le code est java 8.Calcul de couverture erroné dans sonarqube 6.2 sur projet multi module Gradle

En raison du développement piloté par API, les tests API sont écrits en tant que tests abstraits dans les projets API et appelés à partir des projets d'implémentation fournissant les constructeurs pour les tests. Lors de l'analyse du projet sur le serveur sonarqube, la couverture des projets d'implémentation est mesurée correctement, mais les projets API inclus dans les tests des projets IMPL sont sur une couverture de 0,0%. Les résultats de la couverture pour ces projets sont ignorés. Lorsque j'ai simplement utilisé le plugin jacoco, j'ai pu obtenir le même comportement en utilisant simplement le plugin jacoco. Après avoir fait quelques recherches, j'ai trouvé une solution pour obtenir des rapports de jacoco appropriés:

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 
} 

Mon résultat courant est le suivant:

JaCoCo:

  1. JaCoCo (codeCoverageReport-tâche)
    • 73% Couverture des instructions
    • 91% Couverture des branches
  2. Sonar
    • 43,1% Couverture de ligne (lignes seulement ~ 30% pris en compte dans le calcul!)
    • 82,1% Etat couverture (seulement ~ conditions 20% couverts!)

Ainsi, les résultats de couverture dans sonar ne sont pas utilisables. J'ai lu un post annonçant le "sonar.jacoco.reportPaths" -parameter commençant par sonar 6.2 et je pense que java-analyszer 4.4 ou sth. comme ça. Lors de l'ajout de ce paramètre à mon script de build gradle, le script ne se compile plus. Lors de l'ajout des fichiers jacoco .exec au sonar via l'administration du projet sonar, rien ne change.

Ce serait génial s'il y aurait un moyen de gérer sonar pour calculer la couverture correcte.

Répondre

0

Thx @Lance Java! Il m'a poussé à une solution plus propre que celle ci-dessous. Si tous les sous-projets ont des rapports jacoco, cela fonctionne également. Si, comme moi, il n'y a qu'un rapport dans quelques projets, la solution originale semble mieux fonctionner.

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" 
    } 
} 

réponse originale:

Il a fallu un certain temps pour arriver à obtenir les données de couverture correcte au sonar. Il y avait plusieurs problèmes à résoudre.Parfois, la piste a perdu Sonar des changements de jacoco dans les classes, de sorte que les tests nécessaires paramètre:

append=true 

Cela n'a pas fait tout le travail. Il restait un problème à collecter la couverture inter-projets. La meilleure solution consistait donc à forcer jacoco à écrire des données de couverture dans un seul fichier .exec et à le transmettre au sonar.

solution finale se présente comme suit:

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" 
    } 
} 

sonar maintenant a les données de couverture correcte pour mon projet. Après avoir ajouté quelques tests supplémentaires c'est le résultat:

  • Couverture totale 91,6%
  • couverture de ligne 91,7%
  • Couverture Condition 91,3%
  • lignes non couvertes 36
  • Conditions non couvertes 11
  • __gVirt_NP_NNS_NNPS<__ Lines Couvrir 433
  • Tests unitaires 1,114
  • Erreurs de test unitaires 0
  • Unité des échecs des tests 0
  • Ignoré Unité Tests 0
  • Unité de réussite de test (%) 100,0%
  • Durée Test Unit 4 s

Hope cela peut aider certains d'entre vous ...;)

+0

Il y a une tâche [JacocoMerge] (https://docs.gradle.org/4.0/dsl/org.gradle.testing.jacoco.tasks.JacocoMerge.html) qui peut fusionner plusieurs fichiers exec dans un –

+0

va donner un autre essai les prochains jours. N'a pas fonctionné correctement les derniers jours lors des premiers tests. –

+0

Il y a un exemple [ici] (https://github.com/gradle/gradle/blob/28fa962a330ea6085ea324381eec4f31dcf92d1c/subprojects/jacoco/src/integTest/groovy/org/gradle/testing/jacoco/plugins/JacocoPluginMultiVersionIntegrationTest.groovy#L142) dans les tests Gradle qui fusionne plusieurs tâches 'Test' dans un seul projet et génère un rapport fusionné. Vous pouvez adapter cela à votre configuration de multiprojet –

1

Si vos tests sont dans un projet différent des sources sur lesquelles vous souhaitez générer des rapports de couverture, vous devez définir additionalSourceDirs et additionalClassDirs. Par exemple:

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

Thx. Je vais donner un chèque. J'espère que ça va marcher. Répondra bientôt du résultat. –

+0

J'ai été capable de créer un échantillon où votre idée a fonctionné. La meilleure solution pour moi était l'aswer ci-dessous ... –

0

Je ne suis pas sûr de comprendre pourquoi c'est un problème pour certains projets d'avoir jacoco et d'autres projets non. Vous pouvez utiliser les API riches de Gradle (par exemple TaskCollection et Project) pour les trouver dynamiquement.

Par exemple:

[':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)) 
    } 
}