JUnit5でアプリをテストし、カバレッジレポートにJacocoを使用しています。テストが実行されますOkおよびテストレポートが存在します。
ただし、サービスに@Transactionalアノテーションが付けられたメソッドが含まれている場合、Jacocoレポートには次のログがあります
[ant:jacocoReport] Classes in bundle 'my-service' do no match with execution data. For report generation the same class files must be used as at runtime.
[ant:jacocoReport] Execution data for class mypackage/SampleService does not match.
このエラーは、@ Transactionalアノテーションが付けられたすべての@Serviceクラスメソッドで発生します。プレーンクラスのカバレッジは正常に計算されます。
ここにサンプルテストがあります:
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class MyServiceTest {
@Autowired
private SampleService sampleService;
@Test
public void doWork(){
sampleService.doWork();
}
}
正常に動作します。カバレッジはゼロではありません:
public class SampleService {
public void doWork(){
System.out.println("HEY");
}
}
カバー率0%:
public class SampleService {
@Transactional
public void doWork(){
System.out.println("HEY");
}
}
Transactionalはactuallクラスの周りにプロキシを作成します。しかし、Jacocoがこのような一般的な状況を処理するための独創的な方法はありませんか?
さまざまなフラグバリエーションで@EnableAspectJAutoProxyアノテーションを試して、最新のJupiterエンジンとJacocoプラグインが使用されていることを確認しました
これがgradle configです:
subprojects {
test {
useJUnitPlatform()
}
jacocoTestReport {
afterEvaluate {
classDirectories.from = files(classDirectories.files.collect {
fileTree(dir: it, exclude: '*Test.Java')
})
}
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
}
}
助けてくれてありがとう
シングルモジュールインストルメンテーションの例 https://stackoverflow.com/a/31916686/709676 (および@MikaelFによるgradle 5+の更新バージョン)に基づいて、マルチモジュールインストルメンテーションの例を次に示します。
subprojects { subproject ->
subproject.ext.jacocoOfflineSourceSets = [ 'main' ]
task doJacocoOfflineInstrumentation(dependsOn: [ classes, subproject.configurations.jacocoAnt ]) {
inputs.files classes.outputs.files
File outputDir = new File(subproject.buildDir, 'instrumentedClasses')
outputs.dir outputDir
doFirst {
project.delete(outputDir)
ant.taskdef(
resource: 'org/jacoco/ant/antlib.xml',
classpath: subproject.configurations.jacocoAnt.asPath,
uri: 'jacoco'
)
def instrumented = false
jacocoOfflineSourceSets.each { sourceSetName ->
if (file(sourceSets[sourceSetName].output.classesDirs[0]).exists()) {
def instrumentedClassedDir = "${outputDir}/${sourceSetName}"
ant.'jacoco:instrument'(destdir: instrumentedClassedDir) {
fileset(dir: sourceSets[sourceSetName].output.classesDirs[0], includes: '**/*.class')
}
//Replace the classes dir in the test classpath with the instrumented one
sourceSets.test.runtimeClasspath -= files(sourceSets[sourceSetName].output.classesDirs[0])
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
}
ここに完全な例: https://github.com/lizardeye/jacocomultimodulesample
それでも、これは耐久性のあるハックだと思います。これは、gradleまたはjacocoの更新で簡単に壊れる可能性があります