我目前正在使用具有良好覆盖率的gradle multi模块java项目和使用sonarJava插件4.10.0.1026的sonarqube 6.2。我使用的是Gradle 4.0.1,sonarqube插件2.5和jacoco 0.7.9!代码是java 8。
由于API驱动的开发,API测试在API项目中被编写为抽象测试,并从提供测试构造函数的实现项目中调用。
在分析sonarqube服务器上的projekt时,实施项目的覆盖范围是正确测量的,但IMPL项目测试中包含的API项目覆盖率为0.0%。这些项目的覆盖率结果将被忽略。
当简单地使用jacoco插件时,我能够获得相同的行为。在做了一些研究之后,我找到了一个获得正确的jacoco报告的解决方案:
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
}
我目前的结果如下:
JaCoCo:
因此声纳的覆盖率结果不可用。我已经阅读了一篇帖子,宣布" sonar.jacoco.reportPaths" -parameter以sonar 6.2开头,我认为java-analyzer 4.4或者......像那样。将此参数添加到我的gradle构建脚本时,脚本不再编译。通过声纳项目管理将jacoco .exec文件添加到声纳时没有任何变化。
如果有办法管理声纳来计算正确的覆盖范围,那就太好了。
答案 0 :(得分:1)
如果您的测试与您希望覆盖率报告的来源位于不同的项目中,那么您需要设置additionalSourceDirs
和additionalClassDirs
。例如:
evaluationDependsOn ':foo'
task codeCoverageReport(type: JacocoReport) {
additionalSourceDirs.add project(':foo').sourceSets.main.java.sourceDirectories
additionalClassDirs.add project(':foo').sourceSets.main.output.classesDirs
// etc
}
答案 1 :(得分:1)
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文件并将其交给声纳。
最终解决方案如下所示:
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"
}
}
现在声纳为我的项目提供了正确的覆盖率数据。添加一些额外的测试后,结果是:
希望这对你们中的一些人有所帮助......;)
答案 2 :(得分:0)
我不确定我理解为什么只有一些项目才能让jacoco和其他项目没有。您可以使用Gradle丰富的API(例如TaskCollection和Project)动态查找它们。
例如:
[':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))
}
}