【发布时间】:2013-03-19 06:43:43
【问题描述】:
有没有一种简单的方法来判断我缺少哪个分支? IE。我有一些这样的代码:
if (x || y) {
// do stuff
}
在突出显示的报道中,Eclipse 中有一个黄点,上面写着:
错过了 4 个分支中的 1 个
但我想知道缺少哪个分支。
【问题讨论】:
标签: java eclipse code-coverage eclemma
有没有一种简单的方法来判断我缺少哪个分支? IE。我有一些这样的代码:
if (x || y) {
// do stuff
}
在突出显示的报道中,Eclipse 中有一个黄点,上面写着:
错过了 4 个分支中的 1 个
但我想知道缺少哪个分支。
【问题讨论】:
标签: java eclipse code-coverage eclemma
x 和 y 可以是什么?
true || true 为 true(因 JVM 优化未涵盖:如果第一个条件为 true,则第二个条件因短路评估而不会被评估)false || true 是真实
true || false 是真实
false || false 是 假
【讨论】:
|| 运算符的语言规范中,如果第一个操作数的计算结果为真,则不能计算第二个操作数。这是一个硬性功能要求,而不是优化,并且是用 Java 语言而不是 JVM 定义的。
true 时它不能评估第二个操作数,它如何区分true || true 和true || false?我看不出y=true 和y=false 是如何区分的!我认为只有 3 种情况:true、false||true 和 false||false - 你怎么看?这闻起来像是覆盖工具中的错误......!
有一个非常简单的解决方法 - 只需将每个逻辑谓词放在单独的行上,如下所示:
if (x
|| y) {
System.out.println("BRANCH: " + x + ", " + y);
// Do stuff
}
现在,当您运行分析时,标记应直接指向遗漏的分支。添加覆盖率后,您可以以正确的方式重新格式化您的代码。
【讨论】:
在 Eclemma 的父母 jacoco 的 github 存储库上的 open issue 表明,这样的功能实际上有点难以包含。
但是,即使没有 Eclemma 功能,如果目标只是找出在特定情况下遗漏的分支,您也可以检测代码以进行跟踪。最简单的例子是老式的打印语句:
if (x || y) {
System.out.println("BRANCH: " + x + ", " + y);
// Do stuff
}
然后查看输出,看看你实际点击了哪些分支(例如java ... | grep "BRANCH:" | sort | uniq)。 (不是很满意,我知道。)
【讨论】:
return expr1 && expr2这样的行上有同样的错误;我有单元测试,执行返回值为真。所以它一定已经访问了这两个表达式。 ://
答案是true|| true 未被覆盖。
这是因为一旦 JVM 发现第一个条件为真,它就不会运行第二个条件(已优化),这意味着这部分代码永远不会运行。
正如 Maroun 所说,4 个分支中有 3 个将允许条件通过。如果您仍然担心代码覆盖率,可以将条件重构为 && 而不是 ||。
(x || y) 与(!(!x && !y)) 相同,这将允许您测试所有条件,因为现在只有三个分支。
条件的原始形式经常出现在保护语句中:
if (obj == null || obj.hasError())
{
throw new RuntimeException();
}
这将永远不允许您检查 obj 是否为 null 并且有错误,因为它会抛出空指针异常。
如果代码覆盖率很重要,那么只需使用这种形式:
if (!(obj != null && !obj.hasError()))
{
throw new RuntimeException();
}
【讨论】:
| 或 & 除非您故意将操作短路,在这种情况下您永远无法获得完整的分支覆盖。
可能存在来自if 块内的嵌套语句或扩展x 或y 谓词的语句的隐式分支。
阅读: http://emma.sourceforge.net/faq.html#q.fractional.examples
【讨论】:
下面的表达式会是什么结果?
true || true 是 true true || false 是真实
false || true 是真实
false || false 是 假
如果您注意到第一种和第二种情况,当您将第一个参数设置为 TRUE 时,则无需检查第二个参数。
true && true 是 true true && false 是 错误
false && true 是 假
false && false 是 假
或者,如果您看到带有 AND 运算符的场景,如果第一个参数为 FALSE,则您永远不需要检查第二个参数。
因此您永远无法检查 4 个分支中的 1 个分支。
【讨论】:
要获得全面覆盖,避免编译器的隐式选择,您必须将 if 语句重写为两个 as
if (x) {
// do stuff
} else if (y) {
// do the same stuff
}
这将得到全面覆盖,但会被正确标记为冗余代码。看到问题后,我宁愿忍受黄线,也不愿将这种混乱的结构添加到代码中。
【讨论】: