web-dev-qa-db-fra.com

Le générateur de rapport de couverture de code jacoco affiche une erreur: "Les classes du paquet" Rapport de couverture de code "ne correspondent pas aux données d'exécution"

Je génère un rapport jacoco en utilisant la balise jacoco: report. Je reçois des erreurs comme:

[jacoco:report] Classes in bundle 'Code Coverage Report' do no match with execution data. For report generation the same class files must be used as at runtime.
[jacoco:report] Execution data for class xxxxx does not match.
[jacoco:report] Execution data for class yyyyy does not match.

La cible du rapport sur les fourmis ressemble à:

<target name="report">
                <jacoco:report>
                        <executiondata>
                                <file file="${jacocoexec.dir}/${jacocoexec.filename}"/>
                        </executiondata>
                        <!-- the class files and optional source files ... -->
                        <structure name="Code Coverage Report">
                                <classfiles>
                                        <fileset file="./jar/abc.jar"/>
                                </classfiles>
                                <sourcefiles>
                                      <fileset dir="./code/src"/>
                                </sourcefiles>
                        </structure>
                        <!-- to produce reports in different formats. -->
                        <html destdir="${jacoco.report.dir}"/>
                </jacoco:report>
        </target>

Le abc.jar ainsi généré est en utilisant ./code/src seulement. Alors pourquoi donne-t-il de telles erreurs. Une idée?

17
Nishant Lakhara

Vous obtenez l'erreur liée à classID. Il s'agit d'un concept décrit en détail sur le site de documentation JaCoCo. http://www.eclemma.org/jacoco/trunk/doc/classids.html . Il s'agit d'une étape clé pour la prise en charge de plusieurs versions de classe (un serveur d'applications par exemple) dans la même JVM.

Copier une partie de celui-ci ici pour la visibilité.

Que sont les identifiants de classe et comment sont-ils créés?

Les identifiants de classe sont des valeurs entières 64 bits, par exemple 0x638e104737889183 en notation hexadécimale. Leur calcul est considéré comme un détail d'implémentation de JaCoCo. Actuellement, les identifiants sont créés avec une somme de contrôle CRC64 du fichier de classe brute.

Qu'est-ce qui peut provoquer différents identifiants de classe?

Les identifiants de classe sont identiques pour le même fichier de classe exact uniquement (octet par octet). Il existe plusieurs raisons pour lesquelles vous pouvez obtenir différents fichiers de classe. La première compilation Java donneront des fichiers de classe différents si vous utilisez une chaîne d'outils différente:

  • Fournisseur de compilateur différent (par exemple, Eclipse vs Oracle JDK)

  • Différentes versions du compilateur

  • Différents paramètres du compilateur (par exemple, débogage vs non-débogage)

De plus, les fichiers de classe de post-traitement (obscurcissement, AspectJ, etc.) modifieront généralement les fichiers de classe. JaCoCo fonctionnera bien si vous utilisez simplement les mêmes fichiers de classe pour l'exécution ainsi que pour l'analyse. La chaîne d'outils pour créer ces fichiers de classe n'a donc pas d'importance.

Même si les fichiers de classe sur le système de fichiers sont les mêmes, il est possible que les classes vues par l'agent d'exécution JaCoCo soient de toute façon différentes. Cela se produit généralement lorsqu'un autre Java est configuré avant que l'agent JaCoCo ou des chargeurs de classe spéciaux prétraitent les fichiers de classe. Les candidats typiques sont:

  • Cadres moqueurs
  • Serveurs d'applications
  • Cadres de persistance

La même page couvre les solutions possibles.

Quelles solutions de contournement existent pour gérer les classes modifiées lors de l'exécution?

Si les classes sont modifiées au moment de l'exécution dans votre configuration, il existe des solutions pour que JaCoCo fonctionne de toute façon:

  • Si vous utilisez un autre agent Java, assurez-vous que l'agent JaCoCo est spécifié en premier dans la ligne de commande. De cette façon, l'agent JaCoCo devrait voir les fichiers de classe d'origine.
  • Spécifiez l'option classdumpdir de l'agent JaCoCo et utilisez les classes vidées lors de la génération du rapport. Notez que seules les classes chargées seront vidées, c'est-à-dire que les classes qui ne sont pas exécutées du tout n'apparaîtront pas dans votre rapport comme non couvertes.
  • Utilisez l'instrumentation hors ligne avant d'exécuter vos tests. De cette façon, les classes sont instrumentées par JaCoCo avant que toute modification d'exécution puisse avoir lieu. Notez que dans ce cas, le rapport doit être généré avec les classes d'origine, pas avec les classes instrumentées.

Modifié le 22-02-2017

Comment utiliser l'instrumentation hors ligne: Utilisez la tâche ci-dessous fournie par Daniel Atallah .

//Additional SourceSets can be added to the jacocoOfflineSourceSets as needed by 
project.ext.jacocoOfflineSourceSets = [ 'main' ]
task doJacocoOfflineInstrumentation(dependsOn: [ classes, project.configurations.jacocoAnt ]) {
    inputs.files classes.outputs.files
    File outputDir = new File(project.buildDir, 'instrumentedClasses')
    outputs.dir outputDir
    doFirst {
        project.delete(outputDir)
        ant.taskdef(
            resource: 'org/jacoco/ant/antlib.xml',
            classpath: project.configurations.jacocoAnt.asPath,
            uri: 'jacoco'
        )
        def instrumented = false
        jacocoOfflineSourceSets.each { sourceSetName ->
            if (file(sourceSets[sourceSetName].output.classesDir).exists()) {
                def instrumentedClassedDir = "${outputDir}/${sourceSetName}"
                ant.'jacoco:instrument'(destdir: instrumentedClassedDir) {
                    fileset(dir: sourceSets[sourceSetName].output.classesDir, includes: '**/*.class')
                }
                //Replace the classes dir in the test classpath with the instrumented one
                sourceSets.test.runtimeClasspath -= files(sourceSets[sourceSetName].output.classesDir)
                sourceSets.test.runtimeClasspath += files(instrumentedClassedDir)
                instrumented = true
            }
        }
        if (instrumented) {
            //Disable class verification based on https://github.com/jayway/powermock/issues/375
            test.jvmArgs += '-noverify'
        }
    }
}
test.dependsOn doJacocoOfflineInstrumentation

Générez maintenant un rapport à l'aide de "gradlew test jacocoTestReport" commande.

23
Jayan

JaCoCo a besoin des mêmes fichiers de classe pour la génération de rapports que ceux utilisés au moment de l'exécution. En raison de différents compilateurs et/ou d'autres outils modifiant les classes, les classes peuvent être différentes.

6
kkmonlee