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?
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:
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:
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.
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.