web-dev-qa-db-ja.com

エラーを示すjacocoコードカバレッジレポートジェネレーター:「バンドル 'コードカバレッジレポート'のクラスは実行データと一致しません」

Jacoco:reportタグを使用してjacocoレポートを生成しています。次のようなエラーが表示されます。

[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.

Antレポートターゲットは次のようになります。

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

abc.jarそのように生成されるのは、./code/srcのみ。次に、なぜそのようなエラーが発生するのですか。何か案が?

17
Nishant Lakhara

ClassIDに関連するエラーが発生しています。これは、JaCoCo docs-siteで詳細に説明されている概念です。 http://www.eclemma.org/jacoco/trunk/doc/classids.html 。これは、同じJVMでクラスの複数のバージョン(たとえば、アプリケーションサーバー)をサポートするための重要なステップです。

可視性のために、ここにその一部をコピーします。

クラスIDとは何であり、どのように作成されますか?

クラスIDは64ビット整数値です。たとえば、16進表記の0x638e104737889183です。それらの計算は、JaCoCoの実装の詳細と見なされます。現在、IDは生のクラスファイルのCRC64チェックサムで作成されます。

異なるクラスIDの原因は何ですか?

クラスIDは、まったく同じクラスファイル(バイト単位)に対してのみ同一です。異なるクラスファイルを取得する理由はいくつかあります。最初にコンパイルするJavaソースファイルは、異なるツールチェーンを使用すると異なるクラスファイルになります。

  • 異なるコンパイラベンダー(EclipseとOracle JDKなど)

  • 異なるコンパイラバージョン

  • 異なるコンパイラ設定(例:デバッグと非デバッグ)

また、クラスファイルの後処理(難読化、AspectJなど)は通常、クラスファイルを変更します。ランタイムと分析に同じクラスファイルを使用するだけであれば、JaCoCoはうまく機能します。したがって、これらのクラスファイルを作成するためのツールチェーンは重要ではありません。

ファイルシステム上のクラスファイルが同じであっても、JaCoCoランタイムエージェントから見たクラスはとにかく異なる可能性があります。これは通常、別のJavaエージェントがJaCoCoエージェントまたは特別なクラスローダーがクラスファイルを前処理する前に構成されている場合に発生します。典型的な候補は次のとおりです。

  • モックフレームワーク
  • アプリケーションサーバー
  • 永続化フレームワーク

同じページで解決策を説明しています。

ランタイム変更クラスを処理するための回避策はありますか?

セットアップで実行時にクラスが変更された場合、とにかくJaCoCoを動作させるためのいくつかの回避策があります。

  • 別のJavaエージェントを使用する場合は、JaCoCoエージェントがコマンドラインで最初に指定されていることを確認してください。この方法で、JaCoCoエージェントは元のクラスファイルを表示します。
  • JaCoCoエージェントのclassdumpdirオプションを指定し、レポート生成時にダンプされたクラスを使用します。ロードされたクラスのみがダンプされることに注意してください。つまり、まったく実行されていないクラスは、カバーされていないためレポートに表示されません。
  • テストを実行する前に、オフライン計測を使用してください。このようにして、実行時の変更が行われる前に、クラスはJaCoCoによって計測されます。この場合、レポートは計測されたクラスではなく、元のクラスで生成される必要があることに注意してください。

2017年2月22日に編集

オフライン計測の使用方法: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

"gradlew test jacocoTestReport"コマンドを使用してレポートを生成します。

23
Jayan

JaCoCoは、実行時に使用されるのとまったく同じクラスファイルをレポート生成に必要とします。異なるコンパイラやクラスを変更する他のツールが原因で、クラスが異なる場合があります。

6
kkmonlee