在一条语句中测试多种AND / OR条件的覆盖率

时间:2019-01-12 00:26:32

标签: java unit-testing junit code-coverage mc-dc

示例语句:

if (conditionA && conditionB && conditionC && conditionD) {
    return true;
}

我可以为所有2 ^ 4个组合编写单元测试,但是如果添加更多条件,这很容易失控。

涵盖这样的陈述的所有条件的单元测试策略应该是什么?还有其他方法可以使代码更健壮吗?

5 个答案:

答案 0 :(得分:6)

我看到这种情况的方式是1条快乐的道路和4个潜在的故障点。如果每个条件对于返回true都是至关重要的,那么写:

  1. 单个快乐路径单元测试,这是逻辑返回true的唯一情况。还有
  2. 对每个可能导致检查失败的变量进行单元测试,断言单个变量具有阻止条件通过的能力。

我知道可以编写通过这些检查的逻辑,但是当多个变量为false时实际上返回true……但是我真的不会担心这种情况,除非您在宇宙飞船上工作或有生命的东西/涉及死亡。在几乎所有情况下,测试人员都只是在任何变量失败的情况下测试实现是否失败。

答案 1 :(得分:5)

关于此主题的文章很多,您的问题似乎需要MC / DC。

有一个由多个条件组成的谓语可导致一个决策。 适用于问题中谓词的众所周知的覆盖标准包括:

  1. 决策范围:确保总体谓词一次为真,一次为假。
    这将导致两个测试用例,例如(T,T,T,T)和(F,T,T,T)。

  2. 基本条件覆盖范围:确保每个条件都为真和为假。
    这也可以通过两个测试用例来实现:(T,T,T,T)和(F,F,F,F)。
    请注意,基本条件的覆盖范围不一定意味着决策覆盖范围(例如:带有测试用例(T,F)和(F,T)的“ P AND Q”满足基本条件的覆盖范围,但两者都评估为F,因此未达到100%的决策覆盖率)。

  3. 修改后的条件/决策覆盖率(MC/DC)。决策和基本条件覆盖率的组合,“已修改”,因此还要求每个条件必须单独确定结果。 answer by Edwin Buck是有效的MC / DC封面(TTTT,FTTT,TFTT,TTFT,TTTF)。
    通常,在N个条件下,MC / DC需要N + 1个测试用例,而不是2 ^ N个。因此,它在严格度(测试的每个条件)和效率(可能不需要测试所有2 ^ 4)之间取得了良好的平衡。背后的直觉正是the answer by Adam Bates中的推理。

  4. 全部条件覆盖范围:测试所有2 ^ N种可能的组合。

答案 2 :(得分:2)

您可能不需要全部执行2 ^ 4个条件,例如,如果A为假,则甚至不检查其他条件。您也许只用5就可以逃脱

let controller = UISearchController(searchResultsController: nil)  
controller.hidesNavigationBarDuringPresentation = true  
controller.obscuresBackgroundDuringPresentation = false  

controller.searchBar.searchBarStyle = .minimal  

controller.searchResultsUpdater = self  
controller.searchBar.delegate = self  

self.searchController = controller  
self.navigationItem.searchController = controller  

但是正如另一个戴夫所说,根据您的代码,您可能不需要测试所有条件。考虑一下您的测试目标,看看什么是合适的

编辑:avandeursen建议的更改

答案 3 :(得分:2)

我建议采用以下方法

                       A B C D
testTypicalCall()   -> T T T T
testAisFalseFails() -> F T T T
testBisFalseFails(  -> T F T T
testCisFalseFails() -> T T F T
testDisFalseFails() -> T T T F

这捕获了您可能失败的四种独立方法,并且可以推断出,如果将这两种方法组合在一起进行,则至少应触发一种失败测试。

在将来的if语句重构中,它对于抵抗A,B,C和D的重新排列也很强大,并且不依赖于短路逻辑来确保捕获故障条件。 (Justin的回答也很好,但是通过在解决方案中为未检查的值选择真实值,可以提高测试的表现力,并防止错误消息指示错误的非true选项,如果您决定以某种方式报告哪个选项是错误)。

答案 4 :(得分:0)

作为我的答案的简介,我想再次解释一下我们为什么进行软件测试。大多数测试人员都有很大的误解。

  • 我们不会测试软件以证明它没有错误(这是不可能的。已经适用于次要的复杂软件)
  • 我们进行了“建设性测试”,以证明该功能是可以接受的,并且需求或功能是“有效的”。
  • 最重要的是:我们尝试找到尽可能多的错误(“破坏性测试”)。我们将永远找不到所有错误。 SRGM可用于显示深度测试应该进行的程度。

然后,这已经是您对“我的单元测试策略应该是什么?”这个问题的一部分的答案。

我将引用汽车SPICE(PAM 3.1),这是一种众所周知且经过验证的过程模型,过程SWE.4,软件单元验证:

  

“软件单元验证过程的目的是验证软件单元,以提供证据证明软件单元符合软件详细设计和无功能软件要求。”

关于对质量特别是安全性有更高要求的软件的另一组单元测试说明可以从ISO 26262“公路车辆-功能安全性”,第6部分:软件级产品开发中获取,第9章,表10、11、12

软件单元测试方法

Requirements-based test
Interface test
Fault injection test
Resource usage test
Back-to-back comparison test between model and code, if applicable

导出软件单元测试用例的方法

Analysis of requirements
Generation and analysis of equivalence classes
Analysis of boundary values
Error guessing

现在最重要的是,回答问题的第二部分,您应该进行结构覆盖率分析(不是结构测试),以评估测试用例的完整性并证明没有意外的功能。切勿混淆结构测试和结构覆盖范围。

因此,您将测试并检查是否满足要求,并进行结构覆盖率测量以证明这一点。如果覆盖率结果太低,那么您将添加更多测试用例。

推荐的覆盖率指标为MCDC。

当然,您也可以选择许多其他Coverage方法之一。但是,然后您应该在测试策略中给出基本原理,为什么要这么做。

再次查看您的问题:

if (conditionA && conditionB && conditionC && conditionD) 
{
    return true;
}

您似乎正在要求结构测试的建议。我也会回答这个问题,但是请注意,使用这种方法,您只是在测试编译器是否正常工作。

对于手头的布尔表达式(以及其他更复杂的表达式),您可能永远找不到以下错误之一:

错误类别

Expression Negation Fault (ENF)
Sub-Expression Negation Fault (SENF)
Sub-Expression Omission Fault (SEOF)
Literal Negation Fault (LNF)
Literal Omission Fault (LOF)
Literal Reference Fault (LRF)
Literal Insertion Fault (LIF)
Operator Reference Fault (ORF)
Stuck-at-1 Fault (SA1) 
Stuck-at-0 Fault (SA0)
Parenthesis Insertion Fault (PIF)
Parenthesis Omission Fault (POF)
Parenthesis Shift Fault (PSF)

请记住,我在一开始所说的,测试应该发现错误(破坏性测试)。否则,您可能会错过上述错误。

示例:

如果您的需求最初打算在表达式中使用“ OR”而不是“ AND”(错误类ORF),则使用条件覆盖率以及测试向量“ TTTT”和“ FFFF”,将为您提供100%条件覆盖率和100%决策或分支覆盖率。但是您不会找到该错误。 MCDC会发现问题所在。

您还提到了可以测试所有组合(MCC,多条件覆盖)的可能性。对于4个变量,可以。但是对于更多变量,测试执行时间将以几何方式增长。这是无法管理的。这就是为什么定义MCDC的原因之一。

现在,让我们假设您的示例语句正确,并返回到针对表达式的基于MCDC的结构测试的测试用例的定义。

有几种可用的定义,其中大多数都在谈论“唯一原因” MCDC,而忽略了这一事实,同时“掩盖MCDC”和“唯一原因+掩盖MCDC”也是经过认证和认可的标准。对于那些人,您需要忘掉所有以真值表的BlackBox视图开头的教程。谈到结构覆盖或测试,应该很清楚,只有WhiteBox视图可以工作。而且,如果您碰巧使用布尔快捷方式评估的语言进行开发(例如Java,C或C ++),则WhiteBox视图是必不可少的。


对于您的布尔表达式/决定(“ abcd”),并应用布尔快捷方式评估,总共有16个“独特原因” MCDC测试对:

1   Influencing Condition: 'a'  Pair:  0, 15   Unique Cause
2   Influencing Condition: 'a'  Pair:  1, 15   Unique Cause
3   Influencing Condition: 'a'  Pair:  2, 15   Unique Cause
4   Influencing Condition: 'a'  Pair:  3, 15   Unique Cause
5   Influencing Condition: 'a'  Pair:  4, 15   Unique Cause
6   Influencing Condition: 'a'  Pair:  5, 15   Unique Cause
7   Influencing Condition: 'a'  Pair:  6, 15   Unique Cause
8   Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
9   Influencing Condition: 'b'  Pair:  8, 15   Unique Cause
10  Influencing Condition: 'b'  Pair:  9, 15   Unique Cause
11  Influencing Condition: 'b'  Pair: 10, 15   Unique Cause
12  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
13  Influencing Condition: 'c'  Pair: 12, 15   Unique Cause
14  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
15  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

得出建议的MCDC测试集(有多个解决方案):

Test Pair for Condition 'a':    0  15   (Unique Cause)
Test Pair for Condition 'b':    8  15   (Unique Cause)
Test Pair for Condition 'c':   12  15   (Unique Cause)
Test Pair for Condition 'd':   14  15   (Unique Cause)

测试向量:最终结果:0 8 12 14 15

 0:  a=0  b=0  c=0  d=0    (0)
 8:  a=1  b=0  c=0  d=0    (0)
12:  a=1  b=1  c=0  d=0    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

很明显,如果没有布尔捷径评估,则只有4个“独特原因” MCDC测试对:

1  Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
2  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
3  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
4  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

采用一种确定性解决方案:

测试向量:最终结果:7 11 13 14 15

 7:  a=0  b=1  c=1  d=1    (0)
11:  a=1  b=0  c=1  d=1    (0)
13:  a=1  b=1  c=0  d=1    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

我希望,我可以进一步阐明这个问题。

如果您想在工具支持下更详细地研究MCDC,可以看看

MCDC