JavaScript单元测试中的代码覆盖分支是什么?

87
我在 AngularJS 项目中使用 Istanbul 来进行单元测试的代码覆盖率检测。其中有 4 种覆盖类型,它们分别是:

  • 语句覆盖
  • 分支覆盖
  • 函数覆盖
  • 行覆盖

语句、函数和行覆盖还好理解,但我不明白 "分支覆盖" 是什么意思。什么是分支覆盖?

3个回答

123

分支是运行时可以选择走一条路或走另一条路的地方。让我们看一个例子:

if(a) {
    Foo();
}

if(b) {
    Bar();
}

Yay();

当程序执行到第一行时,它可以决定是否进入if(a)语句块内部。或者不进入。在这个阶段,我们已经看到了两条路径(一个分支)。

接下来的语句更有趣。它可以进入if语句块并执行Bar。也可以不这样做。但请记住,我们之前已经有了一个分支。如果调用了Foo,结果可能会有所不同。

因此,我们最终得到四条可能的路径:

  • 不调用Foo,也不调用Bar
  • 调用Foo,不调用Bar
  • 不调用Foo,调用Bar
  • 同时调用FooBar

无论是否调用了FooBar,最后一个Yay语句总是会被执行,因此它不算作一个分支。因此,上面的代码片段包含四条路径/两个分支(调用或不调用Foo(),调用或不调用Bar())。

正如其他答案已经提到的,有许多语句会导致分支(if/switch)。其中一些,但不是全部,包括:

  • 条件循环(如while/for/do-while
  • breakcontinue语句
  • 二元短路运算符(如&&/||
    • 例如,对于给定的foo && bar,如果foofalse,则不必评估bar。同样,对于foo || bar,如果footrue,也不必评估bar
  • 默认参数(如function A(someVar = []) { ... }
    • 这是因为调用该方法被解释为一个if语句。对于每个调用该方法的参数,如果它是undefined,则设置默认参数作为someVar(对于上面的示例)。这将导致存在一个分支。

代码覆盖率工具希望确保您已经测试了所有的分支。最好的方法是测试所有路径,甚至是所有(边缘情况)值,而不仅仅是分支。这样可以确保不会执行任何不想要的行为。


4
感谢您提供详细的回答。 - Evren Kutar
@Arseniy-II 默认参数值如何导致分支?它只是一个不同的值/调用。但我可能错了。 - Caramiriel
@Caramiriel 我在测试时得到了这个分支。我认为从jest的角度来看,它与 let actualVar = someVar || [] 是相同的。所以基本上是“如果 someVar 未定义,则使用 [ ]”。但如果你能检查一下就好了 :) - Arseniy-II

12

代码会分岔,即有多条路线。 分支语句的几个例子是 if/elseswitch 语句。

分支覆盖率跟踪已执行的分支,以确保所有路线都得到适当的测试。


3

来自维基百科:

每个控制结构(如if和case语句)的每个分支(也称为DD-path)是否已执行?例如,对于一个if语句,true和false分支都已执行吗?换句话说,程序中的每条边都执行过了吗?

您需要测试每个控制结构的所有可能情况(如if语句的进入/未进入等,以及switch的所有情况)。分支覆盖率是一种指标,它测量您的测试覆盖了多少总分支数(通常以百分比表示)。


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