Eclemma表示有4个分支中的1个未被覆盖,但是它是哪个分支?

30

有没有简单的方法可以告诉我我缺少哪个分支? 比如,我有这样一些代码:

if (x || y) {
    // do stuff
}

在覆盖率提示中,Eclipse 中有一个黄点,上面写着:

1 of 4 branches missed

但是我想知道哪一个分支缺失了。

7个回答

19

有一个非常简单的解决方法 - 只需将每个逻辑谓词放在单独的一行上,就像这样:

if (x 
    || y) {
    System.out.println("BRANCH: " + x + ", " + y);
    // Do stuff
}

现在当您运行分析时,标记应该直接指向被错过的分支。在添加了覆盖率后,您可以正确地重新格式化代码。


太棒了!顺便说一下,如果Eclipse的“保存时格式化”功能总是把它们放在一行上,请改用文本编辑器编辑文件。 - Noumenon

18

xy可以是什么?

  • true || truetrue(由于JVM优化,第一个条件为true时,不会评估第二个条件,因为采用短路求值)
  • false || truetrue
  • true || falsetrue
  • false || falsefalse

1
问题是,我怎么知道这些分支中哪些没有被执行?我确定不是false/false的情况,因为在某些情况下会执行“else”分支。 - tor
7
难道应该涉及未被覆盖的true || true情况吗? - Jason
1
我认为这个问题的关键在于,有时你会遇到复杂的条件语句,比如foo!= null && foo.equals("bar")。或者我曾经遇到过必须对难以跟踪的过时控制语句进行单元测试的情况。 - Salsero69
2
“因JVM优化而未覆盖”的说法并不完全正确。这不是一种优化:在||运算符的语言规范中,如果第一个操作数为真,则不得评估第二个操作数。这是一个硬性的功能要求,而不是一种优化,并且定义在Java语言中,而不是JVM中。 - SusanW
2
而且,考虑到当第一个操作数为“true”时不得评估第二个操作数,它是如何区分“true || true”和“true || false”的呢?我不明白如何区分 y=true 和 y=false!我认为只有三种情况:true、false||true 和 false||false - 你认为呢?这听起来像是覆盖工具中的错误……! - SusanW
显示剩余2条评论

13

GitHub仓库中的一个未解决问题表明,在Eclemma的父级项目jacoco上实现这样一个功能可能会有一定难度。

但是,即使没有Eclemma的功能,如果目标只是找出特定情况下错过的分支,您可以对代码进行仪器化以进行跟踪。最简单的示例是老式的打印语句:

if (x || y) {
    System.out.println("BRANCH: " + x + ", " + y);
    // Do stuff
}

然后查看输出并确定实际命中的分支(例如:java ... | grep "BRANCH:" | sort | uniq)。 (我知道这不是很令人满意。)


我在像 return expr1 && expr2 这样的行上遇到了相同的错误;我的单元测试期望返回值为 true。因此它必须已经访问了这两个表达式。 :/ - juanmf

6
答案是true || true没有被覆盖。
这是因为一旦JVM发现第一个条件为真,它就不会运行第二个条件(它被优化了),这意味着代码的那部分永远不会运行。
正如Maroun所说,4个分支中有3个将允许条件通过。如果你仍然担心代码覆盖率,你可以重构条件为&&而不是||(x || y)(!(!x && !y))相同,这将允许您测试所有条件,因为现在只有三个分支。
条件语句的原始形式通常在守卫语句中看到:
if (obj == null || obj.hasError())
{
    throw new RuntimeException();
}

这种方式永远无法检查obj是否为null并且有错误,因为它会抛出Null Pointer Exception异常。

如果代码覆盖率很重要,那么请使用以下形式:

if (!(obj != null && !obj.hasError()))
{
    throw new RuntimeException();
}

1
除非你有意短路操作,否则可以使用渴望的运算符|&,否则你永远无法获得完整的分支覆盖。 - tkokasih
1
@BrettPyke 为什么在“&&”的情况下有三个分支? - ishan3243
9
如果你将(x || y)转换为!(!x && !y),你会面临与!(false && false)表达式相同的快捷问题。 - Leonid Glanz
@LeonidGlanz 没错。如果覆盖工具中存在错误,它会错误地评估OR条件而不是AND条件,那么这是一件事。但是对逻辑进行反转并不改变只有4种情况且只有3种可达的事实。 - SusanW

0

是的,我明白了。x和y布尔值有4种不同的可能组合,我猜只有其中三种被观察到了。问题是,我怎么知道哪种情况没有发生?或者等价地说,哪些情况被观察到了? - tor
“1 of 4 branches covered” 表示有 3 个分支未被覆盖。我认为(从块内覆盖高亮显示中)哪些代码路径未被覆盖是显而易见的。 - Tim Bender
1
抱歉,我完全犯了错!实际上消息是“4个分支中有1个被忽略了。”我会立即更新... - tor

0

以下表达式的结果将是什么?

  • true || truetrue
  • true || falsetrue
  • false || truetrue
  • false || falsefalse

如果您注意到在第1和第2种情况下,当第1个参数为TRUE时,您不需要检查第2个参数。

  • true && truetrue
  • true && falsefalse
  • false && truefalse
  • false && falsefalse

或者,如果您看到使用AND运算符的情况,如果第一个参数为FALSE,则永远不需要检查第二个参数。

因此,您永远无法检查4个分支中的1个分支。


1
那么,这是否意味着覆盖工具警告未测试完全无法到达的分支?这听起来像是一个错误。 - SusanW

-1
为了获取完整的覆盖范围,避免编译器的隐含选择,您必须将if语句重写为两个。
if (x) {
    // do stuff
} else if (y) {
    // do the same stuff
}

这将获得完整的覆盖范围,但会被正确标记为冗余代码。我宁愿在看到问题后接受黄色线条,也不愿将这种混乱的结构添加到代码中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接