Java Gradle多模块项目sonarqube 6.2中的覆盖计算错误
我目前正在使用一个覆盖范围很好的gradle多模块java项目,以及sonarqube 6.2和sonarJava插件4.10.0.1026。我正在使用Gradle 4.0.1、sonarqube插件2.5和jacoco 0.7.9!代码是Java8 由于API驱动的开发,API测试在API项目中作为抽象测试编写,并从为测试提供构造函数的实现项目中调用 分析sonarqube服务器上的项目时,正确测量了实施项目的覆盖率,但IMPL项目测试中包含的API项目的覆盖率为0.0%。这些项目的覆盖率结果将被忽略 当我仅仅使用jacoco插件时,我就能够得到同样的行为。在做了一些研究之后,我找到了一个获得正确的jacoco报告的解决方案:Java Gradle多模块项目sonarqube 6.2中的覆盖计算错误,java,gradle,sonarqube,code-coverage,jacoco,Java,Gradle,Sonarqube,Code Coverage,Jacoco,我目前正在使用一个覆盖范围很好的gradle多模块java项目,以及sonarqube 6.2和sonarJava插件4.10.0.1026。我正在使用Gradle 4.0.1、sonarqube插件2.5和jacoco 0.7.9!代码是Java8 由于API驱动的开发,API测试在API项目中作为抽象测试编写,并从为测试提供构造函数的实现项目中调用 分析sonarqube服务器上的项目时,正确测量了实施项目的覆盖率,但IMPL项目测试中包含的API项目的覆盖率为0.0%。这些项目的覆盖率结果
task codeCoverageReport(type: JacocoReport) {
description "Creates a unified JaCoCo test report for the project."
// Gather execution data from all subprojects
// (change this if you e.g. want to calculate unit test/integration test coverage separately)
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
// Add all relevant sourcesets from the subprojects
subprojects.each {
sourceSets it.sourceSets.main
}
reports {
xml.enabled true
html.enabled true
html.destination file("${buildDir}/reports/jacoco")
csv.enabled false
}
}
// always run the tests before generating the report
codeCoverageReport.dependsOn {
subprojects*.test
}
我目前的结果如下:
雅科科:
- 73%的教学覆盖率
- 91%的分行覆盖率
- 43.1%的线路覆盖率(计算中仅考虑约30%的线路!)
- 82.1%的条件覆盖率(仅覆盖约20%的条件!)
如果有一种方法可以管理sonar来计算正确的覆盖率,那就太好了。如果您的测试与您想要覆盖率报告的源位于不同的项目中,那么您需要设置
附加源dirs
和附加类dirs
。例如:
evaluationDependsOn ':foo'
task codeCoverageReport(type: JacocoReport) {
additionalSourceDirs.add project(':foo').sourceSets.main.java.sourceDirectories
additionalClassDirs.add project(':foo').sourceSets.main.output.classesDirs
// etc
}
Thx@Lance Java!他把我推到一个比下面更干净的解决方案。如果所有子项目都有jacoco报告,那么这种方法也可以。如果像我一样,只有少数项目有一份报告,那么最初的解决方案似乎效果更好
apply plugin: 'base'
apply plugin: 'org.sonarqube'
[...]
allprojects {
apply plugin: 'java'
apply plugin: "jacoco"
[...]
test {
[...]
jacoco {
append=true
}
}
}
[...]
task jacocoMerge( type: JacocoMerge ) {
dependsOn( subprojects.jacocoTestReport.dependsOn )
mustRunAfter( subprojects.jacocoTestReport.mustRunAfter )
destinationFile = file( "${buildDir}/jacoco/mergedTests.exec" )
executionData = files( subprojects.jacocoTestReport.executionData )
.filter { jacocoReportFile -> jacocoReportFile.exists() }
}
tasks.sonarqube.dependsOn jacocoMerge
[...]
sonarqube {
properties {
[...]
property "sonar.jacoco.reportPath", "${buildDir}/jacoco/*.exec"
}
}
原始答复: 要把正确的覆盖范围数据传送到声纳需要一些时间。有许多问题需要解决。有时Sonar无法跟踪jacoco在类中的变化,因此测试需要参数:
append=true
这并没有完成所有的工作。在收集跨项目覆盖率方面仍然存在一个问题。因此,最好的解决方案是强制jacoco将覆盖率数据写入单个.exec文件,并将其交给sonar
最终解决方案如下所示:
apply plugin: 'base'
apply plugin: 'org.sonarqube'
[...]
allprojects {
apply plugin: 'java'
apply plugin: "jacoco"
[...]
test {
[...]
jacoco {
append=true
destinationFile = file( "${rootProject.buildDir}/jacoco/jacocoTest.exec" )
}
}
}
[...]
sonarqube {
properties {
[...]
property "sonar.jacoco.reportPath", "${buildDir}/jacoco/*.exec"
}
}
现在sonar为我的项目提供了正确的覆盖数据。添加一些附加测试后,结果如下:
- 总覆盖率91.6%
- 线路覆盖率91.7%
- 条件覆盖率91.3%
- 未覆盖线路36
- 未覆盖的条件11
- 第433行
- 单元测试1114
- 单元测试错误0
- 单元测试失败0
- 已跳过单元测试0
- 单元测试成功率(%)100.0%
- 单元测试持续时间4s
希望这能对你们中的一些人有所帮助……;) 我不太明白为什么只有一些项目有jacoco,而其他项目没有。您可以使用Gradle的富API(例如和)动态查找它们 例如:
[':project1',':project3',':project5'],每种{
项目(it){
应用插件:“java”
应用插件:“jacoco”
}
}
项目(“:合并”){
集合jacocoProjects=allprojects.findAll{it.plugins.hasPlugin('jacoco'}
评估依赖于Jacoco项目
任务jacocoMerge(类型:jacocoMerge){
dependsOn JacoProject*.tasks.withType(测试)
executionData JacoCoProject*.tasks.withType(测试)
}
任务合并报表(类型:JacocoReport){
德彭森·贾科科梅
executionData JacoComge.destinationFile
添加(文件(jacocoProjects*.sourceset*.java.srcDirs))
添加(文件(jacocoProjects*.sourceset*.output.classesDir))
}
}
Thx。我会检查一下。希望我能让它工作。我会很快回复结果。我能够在你的想法起作用的地方创建一个样本。对我来说,最好的解决方案是下面的答案…@这位先生“下面的答案”没有帮助。你应该A.投票选出正确答案,B.指定写答案的人的用户名,以便稍后有人知道你的意思。有一项任务可以将多个exec文件合并到一个文件中,并在接下来的几天内再次尝试。在第一次测试的最后几天工作不正常。下面是一个示例在gradle测试中,将多个测试任务合并到单个项目中,并生成合并报告。您可以调整此多项目设置,感谢现在有时间修改我的项目。覆盖率结果是相同的,但在我看来更干净,管道胶带更少……;)正在更新接受的答案。您应该在调用分析之前将更改推送到存储库。JaCoCo合并解决方案更干净,但不像其他解决方案那样获得跨项目覆盖。已放弃api和测试UTIL项目的覆盖率->91%覆盖率->60%(仅使用唯一具有测试的impl项目)。原因很简单,只有impl项目有.exec文件。。。
[':project1', ':project3', ':project5'].each {
project(it) {
apply plugin: 'java'
apply plugin: 'jacoco'
}
}
project(':merger') {
Collection<Project> jacocoProjects = allprojects.findAll { it.plugins.hasPlugin('jacoco' }
evaluationDependsOn jacocoProjects
task jacocoMerge(type: JacocoMerge) {
dependsOn jacocoProjects*.tasks.withType(Test)
executionData jacocoProjects*.tasks.withType(Test)
}
task mergedReport(type: JacocoReport) {
dependsOn jacocoMerge
executionData jacocoMerge.destinationFile
sourceDirectories.add(files(jacocoProjects*.sourceSets*.java.srcDirs))
classDirectories.add(files(jacocoProjects*.sourceSets*.output.classesDir))
}
}