语句覆盖和决策覆盖的区别

40

语句覆盖率确保代码中的每个语句至少执行一次。
决策/分支覆盖率测试每个决策的每个分支/输出是否都被覆盖,即执行所有真假分支中的语句。
但这不是一样的吗?在语句覆盖率中,我需要执行所有语句,因此我想它只能通过运行所有可能的方法来完成。 我知道我在这里错过了什么。


1
我猜这个问题更适合在Programmers.StackExchange.com上问。顺便说一下,决策覆盖率和分支覆盖率不是同一回事! - Adriano Repetti
@Adriano 是的,维基百科是这样说的,但很多其他来源都说是一样的。 - John V
不仅是维基百科,"decision"在编程中的正式定义是每个条件进入分支代码路径的决定(那么分支就是整个条件)。例如,在C/C++中的短路。你可以决定将它们用作同义词或不用。 - Adriano Repetti
1
此外,即使已执行包含某个语句的分支,该语句也可能不会被执行,因为存在跳转、异常和/或其他异步条件(锁定、信号、事件)等原因。这就是为什么决策覆盖率和语句覆盖率可能不同的原因。 - Adriano Repetti
5个回答

58
Paul的回答并不完全正确,至少我是这么认为的(根据ISTQB的定义)。语句覆盖、决策/分支覆盖和条件覆盖之间存在相当大的差异。 我将使用其他回答中的示例,但稍作修改,以便能够展示所有三种测试覆盖的例子。这里编写的测试为每种类型提供了100%的测试覆盖率。
if (a || b) {
    test1 = true;
}
else {
    if (c) {
      test2 = true;
    }
}

我们这里有两个语句 - if(a||b) 和 if(c),为了充分解释这些覆盖差异:
1. 语句覆盖要求至少执行每个语句一次,所以我们只需要两个测试:
- a=true 和 b=false - 这样我们就可以通过路径 if(a||b) true -> test1 = true - a=false, b=false 和 c=true - 这样我们就可以通过路径 if(a||b) false -> else -> if(c) true -> test2 = true 这样我们就执行了每个语句。
2. 分支/决策覆盖需要再进行一次测试:
- a=false, b=false 和 c=false - 这会导致我们执行第二个 if,但我们执行的是该语句的 false 分支,而在语句覆盖中没有执行过。
这样我们就测试了所有的分支,意味着我们经过了所有的路径。
3. 条件覆盖需要再进行一次测试:
- a=false, b=true - 这会通过与第一个测试相同的路径,但执行了 OR 语句中的另一个决策。
那样我们就测试了所有的条件,也就是说我们经过了所有的路径(分支),并且用每个可能的条件触发了它——第一个“if”语句在第一次测试中为真是因为a=true触发了它,在最后一次测试中也是因为b=true触发了它。当然,有人可能会争论a=true和b=true的情况也应该被测试,但是当我们检查“或”运算符的工作原理时,我们会发现这是不必要的,而且变量c可以是任何值,因为在这些测试中它没有被评估。
至少我是这样解释的。如果有人还感兴趣的话 :)
编辑:在我最近找到的大多数资料中,决策/分支覆盖这些术语是等价的,而我所描述的决策覆盖实际上是条件覆盖,因此更新了答案。

2
我认为那不正确。根据ISTQB词汇表(http://astqb.org/glossary/)的定义:“语句覆盖:测试套件执行的可执行语句百分比。”在你的“语句覆盖”示例中,`test1 = true;`从未被执行,但它显然是一个可执行语句。 - Frank Schmitt
但是test1不是语句,它是变量,在这种情况下是我们可以到达的边缘。'if'是语句(确切地说是条件语句)。也许我在这里漏掉了什么,但我是这样理解的。 - Faflok
5
test1 = true; 是一个变量赋值语句,因此是可执行的语句。 - Frank Schmitt
1
@FrankSchmitt 我读了一些内容并好好思考了一下,我认为你说得对 - 每个语句都是你所说的意思。我已经调整了我的示例,使其更符合我想要展示的内容。感谢你的帮助。 - Faflok
2
第三项是错误的,因为判定覆盖不需要对复杂决策点中的每个单独的条件进行练习。当需要这样做时,我们就有了条件覆盖。 - Rogério
显示剩余2条评论

47

如果测试具有完全的分支覆盖,则可以说它也具有完全的语句覆盖,但反之不成立。

100%分支覆盖=> 100%语句覆盖

100%语句覆盖不能暗示100%分支覆盖

原因在于,在分支覆盖中除了执行所有语句外,我们还应该验证测试是否执行了所有分支,这可以解释为覆盖控制流分支中的所有边缘。

if(a){
   if(b){
     bool statement1 = true;
   }
}

假设 a = true, b = true,将会得到100%的语句覆盖率,但是不会得到分支覆盖率。

enter image description here

在分支覆盖率中,我们需要覆盖所有的边缘,这些边缘在上面图片中标示为红线,而在语句覆盖率中我们忽略了它们。


好的回答,不过我的下一个问题是: 如果“if”语句有一个“else”,假设在else块内有语句,那么else就必须被完全覆盖以完成语句覆盖。分支/行覆盖之间的差异是否只是所有没有“else”的“if”语句?还是还有其他例子? - wheresmycookie
因此,分支覆盖还包括明确地不执行某些语句,而语句覆盖实际上无法做到这一点。 - Timmmm

6
很好的问题。我经常使用的解释是,没有else分支的if语句仍然有一个不可见的“空”else语句:
  • 普通语句覆盖要求实际存在的所有语句都被执行。

  • 分支覆盖要求即使是不可见的else分支也要被执行。

类似的情况也发生在没有默认情况的switch语句和repeat-until循环中。分支覆盖要求执行默认情况,并且至少执行两次repeat-until循环。

一个代码示例:

if (passwordEnteredOK()) {
    enterSystem();
} 
/* Invisible else part 
else {
  // do nothing
}
*/

使用语句覆盖只需检查您能否使用系统的正确密码。使用分支覆盖还要测试,使用错误密码时,您将无法进入系统。


3

您可能会有这样的语句:

if(a || b || (c && d && !e)) {
    test1 = true;
} else {
    test2 = false;
}

如果您的代码覆盖率显示test1和test2两行都被触发,那么您已经具有语句覆盖率,但是要获得完整的分支覆盖率,您需要测试当a为真时,当a为假但b为真时,当a和b都为假但c和d为真且e为假时等所有可能性的组合。
分支覆盖率涵盖了每个分支选择的潜在组合,因此更难以实现100%的覆盖率。

不知道为什么这个回答从未被投票选中。解释得非常好! - Christopher Wirt
7
这是错误的。分支覆盖只需要覆盖控制流图中的所有边缘。布尔评估会分成两个边缘。查看上面的答案获取正确答案。 - Outlier
5
您所描述的是条件覆盖,而不是分支覆盖。 - user1171983

0
关键在于理解“覆盖单位”的概念:对于语句覆盖,它们是可执行的代码行;对于决策覆盖,它们是代码中所有可能的决策节点结果。
好好想一想。
这就是为什么完全的决策覆盖可以保证完全的语句覆盖,但反过来则不行。

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