包中的 Jacoco 类与事务方法不匹配

Erm*_*tar 6 java spring gradle jacoco spring-boot

我正在使用 JUnit5 测试应用程序并使用 Jacoco 进行覆盖率报告。测试执行正常,并提供测试报告。

但是,如果服务包含方法,Jacoco 报告有以下日志,用@Transactional 注释

[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. 
Run Code Online (Sandbox Code Playgroud)

所有@Service 类方法都会发生此错误,用@Transactional 注释,普通类覆盖率计算正常。

这是一个示例测试:

@SpringBootTest
@ExtendWith(SpringExtension.class)
public class MyServiceTest {

    @Autowired
    private SampleService sampleService;

    @Test
    public void doWork(){
        sampleService.doWork();
    }
}
Run Code Online (Sandbox Code Playgroud)

工作正常。覆盖率非零:

public class SampleService {

    public void doWork(){
        System.out.println("HEY");
    }
}
Run Code Online (Sandbox Code Playgroud)

0% 覆盖率:

public class SampleService {

    @Transactional
    public void doWork(){
        System.out.println("HEY");
    }
}
Run Code Online (Sandbox Code Playgroud)

事务创建围绕实际类的代理。但是,难道 Jacoco 没有一种开箱即用的方式来处理这种常见情况吗?

我已经尝试过使用不同标志变化的 @EnableAspectJAutoProxy 注释,检查是否使用了最新的 Jupiter 引擎和 Jacoco 插件

这是gradle配置:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏

gyb*_*ndi 3

我在一个测试项目中进行了尝试,与您所描述的类似,但是我无法重现该问题。我发现你的项目和我的项目之间的唯一区别是我使用了 Maven 而不是 gradle。

这是测试项目: https: //github.com/gybandi/jacocotest

这是它的 jacoco 结果(使用 org.springframework.transaction.annotation.Transactional 注释): 雅可可测试报告

如果这对你没有帮助,你可以将你的测试项目上传到github或其他地方吗?

编辑: @MikaelF 发布了另一个答案的链接,其中显示了如何为 jacoco 添加离线检测。

在我将以下块添加到 build.gradle 后,那里描述的解决方案对我有用:

task instrument(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
            if (file(sourceSets.main.java.outputDir).exists()) {
                def instrumentedClassedDir = "${outputDir}/${sourceSets.main.java}"
                ant.'jacoco:instrument'(destdir: instrumentedClassedDir) {
                    fileset(dir: sourceSets.main.java.outputDir, includes: '**/*.class')
                }
                //Replace the classes dir in the test classpath with the instrumented one
                sourceSets.test.runtimeClasspath -= files(sourceSets.main.java.outputDir)
                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 instrument
Run Code Online (Sandbox Code Playgroud)

jacoco 插件的 github 上似乎也有关于此问题的公开票: https: //github.com/gradle/gradle/issues/2429