jacoco 分支覆盖和声纳条件覆盖有啥区别?

Posted

技术标签:

【中文标题】jacoco 分支覆盖和声纳条件覆盖有啥区别?【英文标题】:What is the difference between jacoco branch coverage and Sonar condition coverage?jacoco 分支覆盖和声纳条件覆盖有什么区别? 【发布时间】:2018-09-27 11:22:34 【问题描述】:

我正在尝试使用 SonarQube 扫描仪(版本 3.1.0.1141)分析 java 代码。

SonarQube 版本:5.6.6 Sonar Java 插件版本:4.12.0.11033 jacoco 版本:0.8.0

我已经用这些属性填充了 sonar-project.properties:

# Sonar sources and metadata
sonar.language=java
sonar.sources=src/main
sonar.java.source=1.8
sonar.sourceEncoding=UTF-8
sonar.java.binaries=target/classes
sonar.java.libraries=target/lib

sonar.tests=src/test
sonar.java.coveragePlugin=jacoco
sonar.junit.reportsPath=target/surefire-reports
sonar.surefire.reportsPath=target/surefire-reports

虽然 jacoco 报告给了我一个班级的这个结果:

覆盖率:84% 分支机构覆盖率:71% 错过:9 复杂度:24 未命中:6 行数:69 未命中:0 方法:8 未命中:0 类:1

SonarQube 显示度量:

条件覆盖率62.5% 覆盖率81.7% 线路覆盖率92.8% 要覆盖的行 69 整体状况覆盖率62.5% 整体覆盖率81.7% 全线覆盖率92.8% 总体未覆盖分支15 整体未覆盖线 5 未覆盖的分支15 未覆盖的线 5

根据sonar metric definition page,条件覆盖的声纳键是branch_coverage,所以我认为条件和分支覆盖是一回事。

如何解释不同的结果?

【问题讨论】:

可能还取决于JDK版本,见***.com/questions/36942950/…。你用的是哪个版本? 感谢您的回答。我用jdk1.8.0_144 【参考方案1】:

假设你有一些构造

if(a == 1 && b == 2) 
  //do this
 else 
  //do that

你有两个分支

这样做 这样做

还有两个条件

a == 1 (cond1) b == 2 (cond2)

如果你有两个测试用例

测试(a == 1,b == 2) 测试(a == 2,b == 2)

你覆盖了两个分支,因为 (cond1 && cond2) 的组合条件要么为假要么为真,

但是你只完全覆盖了 cond1 并且只覆盖了 cond2 的一半,即 75% 的条件覆盖率。

要获得完整的条件覆盖,您需要额外的测试

测试(a == 1,b == 1)

编辑

这两个工具都使用每行的分支信息来计算覆盖率。 我对我的一些代码进行了测试,“覆盖条件”(Sonarqube)的数量与 Jacoco 报告中的“分支”总数相匹配——但我使用了 jacoco 和 Sonarqube/sonar-java 的最新版本。所以除了名称之外,措施是/应该是相同的。

但鉴于您提供的数字,您的分析总体上似乎有些奇怪。不仅百分比值不同,而且绝对值也不同(Jacoco 中的 9 个未发现分支与 Sonarqube 中的 15 个未发现分支)。

所以我检查了您正在使用的版本 - jacoco 0.8.0 和使用 jacoco 0.7.9 的 sonar-java 插件 v4.11.0.11033。

release notes for Jacoco 0.8.0阅读

在创建报告期间,各种编译器生成的工件被过滤掉,否则需要不必要的,有时甚至是不可能的技巧来避免部分或遗漏的覆盖:

方法 valueOf 和枚举类型的值 (GitHub #491)。 私有的空无参数构造函数 (GitHub #529)。 使用@lombok.Generated 注释的方法可以更好地与 Lombok >= 1.16.14 集成。 Rüdiger zu Dohna (@t1) (GitHub #513) 的初步分析和贡献。 使用 @groovy.transform.Generated 注释的方法可以更好地与 Groovy >= 2.5.0 集成。感谢 Andres Almiray (@aalmiray) 将注释添加到 Groovy (GitHub #610)。 同步块的部分字节码 (GitHub #501)。 try-with-resources 语句的部分字节码 (GitHub #500)。 finally 块的部分字节码 (GitHub #604)。 java.lang.String 值上 switch 语句的部分字节码 (GitHub > #596)。

所以我最好的猜测是,Jacoco 0.8.0 生成的报告过滤掉了一些提到的生成的工件,有效地减少了分支的总数。然而,Sonar-Java 使用 Jacoco 0.7.9,它不会过滤掉生成的工件,因此数量更高(覆盖率更低)。

也许您应该将您的 jacoco 版本降级到 0.7.9 或升级 sonar-java 插件。

【讨论】:

这个关于分支和条件覆盖之间差异的解释很清楚。但是 Jacoco 分支覆盖已经考虑了综合条件。它似乎只是声纳和 jacoco 之间的不同术语(分支和条件)。 感谢杰拉德的分析。 Sonar java 插件在 5.2 版本中引入了 jacoco 0.8.0。由于 Sonar 5.6.6 版本,我暂时无法将插件更新到此版本。所以我将 jacoco 版本降级为 0.7.9,报告显示条件覆盖率为 62%。未覆盖的分支数量仍然存在差异(jacoco 为 13,Sonarqube 为 15)

以上是关于jacoco 分支覆盖和声纳条件覆盖有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

将 Jacoco 代码覆盖率发布到声纳的命令

结合声纳的 Jacoco 测试覆盖率

Sonarqube 覆盖结果模块名称用法

使用 Jacoco 从 Sonar 中的条件覆盖范围中排除 groovy slf4j 日志记录

jacoco增量代码覆盖率

SonarQube + Jacoco - 无法读取 Koin 模块测试覆盖率