|
逻辑覆盖是以程序内部的逻辑结构为基础的设计用例的技术。
根据覆盖目标的不同和覆盖源程序语句的详尽程度,逻辑覆盖又可分为:
1. 语句覆盖(SC)
2. 判定覆盖(DC)
3. 条件覆盖(CC)
4. 条件/判定覆盖(CC)
5. 条件组合覆盖(MCC)
6. 修正判定条件覆盖(MCDC)
7. 点覆盖
8. 边覆盖
9. 路径覆盖
几种逻辑覆盖标准发现错误的能力呈由弱至强的变化。
下面我们来逐一举例详解:
1语句覆盖(SC):
语句覆盖是指选择足够的测试用例,使得运行这些测试用例时,被测程序的每一个语句至少执行一次,其覆盖标准无法发现判定中逻辑运算的错误。
我们看下面的被测试代码:
int foo(int a, int b)
{
return a / b;
}
假如我们的测试人员编写如下测试案例:
TeseCase: a = 10, b = 5
测试人员的测试结果会告诉你,他的代码覆盖率达到了100%,并且所有测试案例都通过了。然而遗憾的是,我们的语句覆盖率达到了所谓的100%,但是却没有发现最简单的Bug,比如,当我让b=0时,
会抛出一个除零异常。
简言之,语句覆盖,就是设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。这里的“若干个”,意味着使用测试用例越少越好。
语句覆盖率的公式可以表示如下:
语句覆盖率=可执行的语句总数/被评价到的语句数量 x 100%
2判定覆盖(DC)
判定覆盖是设计足够多的测试用例,使得程序中的每一个判断至少获得一次“真”和一次“假”,即使得程序流程图中的每一个真假分支至少被执行一次。
但若程序中的判定是有几个条件联合构成时,它未必能发现每个条件的错误。
例:
int a,b;
if(a || b)
执行语句1
else
执行语句2
要达到这段程序的判断覆盖,我们采用测试用例:
1)a = true , b = false;
2)a = false, b = false
3条件覆盖(CC)
条件覆盖是指选择足够的测试用例,使得运行这些测试用例时,判定中每个条件的所有可能结果至少出现一次,但未必能覆盖全部分支。
例:
int a,b;
if(a || b)
执行语句1
else
执行语句2
要达到这段程序的条件覆盖,我们采用测试用例:
1)a = true , b = false ;
2)a = false, b = true
4判定/条件覆盖(CDC)
判定/条件覆盖是使判定中每个条件的所有可能结果至少出现一次,并且每个判定本身的所有可能结果也至少出现一次。
例:
int a,b;
if(a || b)
执行语句1
else
执行语句2
要达到这段程序的判定/条件覆盖,我们采用测试用例:
1)a = true , b = true;
2)a = false, b = false
5条件组合覆盖(MCC)
选择足够的测试用例,使得每个判定中条件的各种可能组合都至少出现一次。显然,满足“条件组合覆盖”的测试用例是一定满足“判定覆盖”、“条件覆盖”和“判定/条件覆盖”的。
例:
int a,b;
if(a || b)
执行语句1
else
执行语句2
要达到这段程序的判定/条件覆盖,我们采用测试用例:
1)a = true , b = true;
2)a = false, b = false
3)a = true, b = false
4)a = false, b = ture
6修正判定条件覆盖(MC/DC)
MC/DC首先要求实现条件覆盖、判定覆盖,在此基础上,对于每一个条件C,要求存在符合以下条件的两次计算:
1)条件C所在判定内的所有条件,除条件C外,其他条件的取值完全相同;
2)条件C的取值相反;
3)判定的计算结果相反。
核心意思是每个条件都要独立影响判定结果。为什么说“两次计算”,而不是“两个用例”呢?当循环中有判定时,一个用例下同一判定可能被计算多次,每次的条件值和判定值也可能不同,因此,一个
用例就可能完成循环中判定的MC/DC。
MC/DC是条件组合覆盖的子集。条件组合覆盖要求覆盖判定中所有条件取值的所有可能组合,需要大量的测试用例,实用性较差。MC/DC具有条件组合覆盖的优势,同时大幅减少用例数。满足MC/DC
的用例数下界为条件数+1,上界为条件数的两倍,例如,判定中有三个条件,条件组合覆盖需要8个用例,而MC/DC需要的用例数为4至6个。如果判定中条件很多,用例数的差别将非常大,例如,判定中有
10个条件,条件组合覆盖需要1024个用例,而MC/DC只需要11至20个用例。
下面是MC/DC的示例:
代码:
int func(BOOL A, BOOL B, BOOL C)
{
if(A && (B || C))
return 1;
return 0;
}
用例:
对于条件A,用例1和用例2,A取值相反,B和C相同,判定结果分别为1和0;
对于条件B,用例1和用例3,B取值相反,A和C相同,判定结果分别为1和0;
对于条件C,用例3和用例4,C取值相反,A和B相同,判定结果分别为0和1。
9路径覆盖(PC)
MC/DC被称为“最严格的标准”,但这种说法是将条件组合覆盖和路径覆盖排除在外为基础的。MC/DC显然不如条件组合覆盖严格,但是条件组合覆盖需要太多用例,实际应用中难以做到,所以排除,
那么,路径覆盖是否也难以做到?使用先进的工具,对于一般的代码,实现路径覆盖还是可能的。另外,路径代表了从函数入口到出口的所有可能的代码组合,这些组合会不会出问题?只有路径覆盖能发现,
这与MC/DC侧重于判定内的条件的组合关系是完全不同的。
MC/DC与路径覆盖的侧重点不同,两者都有其优势和局限性,如果组合起来,优势互补,形成“MC/DC-路径覆盖”,就是真正意义上的“最严格的标准”了。
有些程序,路径数量可能大得惊人,可用以下规则和方法减少路径数量:
计算路径时,不考虑循环的次数,将循环结构视为循环体“至少执行一次”和“从不执行”两个分支;
不考虑条件的计算结果只考虑判定的计算结果,条件间的组合关系由条件覆盖、C/DC和MC/DC负责;
一个分支如果不可达,通过该分支的所有路径也不可达,可以让工具自动排除;
当代码很复杂时,理想的处置方式是将部分代码独立为函数,如果做不到,可以让工具来模拟,即在逻辑结构图中,将部分代码临时屏蔽,被屏蔽的代码视为一个函数调用。交替屏蔽可以既减少路径数
量,又保证路径覆盖的效果。
对于一般复杂度的代码,采用以上规则和方法后,路径数量和用例数量可以维持在一个现实可覆盖的的范围内。
路径覆盖的主要缺陷是:不相关的逻辑块会组合出大量没有意义的路径。一个函数的路径,可能达到几万条甚至几百万条。如果路径超过100条,通常路径覆盖就没有意义了。对于一般企业来说,建议用
MC/DC作为统一的覆盖标准,只有特别关键的代码,才要求完成“MC/DC-路径覆盖”。
路径覆盖要求设计足够多的测试用例,在[url=]白盒测试[/url]法中,覆盖程度最高的就是路径覆盖,因为其覆盖程序中所有可能的路径。
对于比较简单的小程序来说,实现路径覆盖是可能的,但是如果程序中出现了多个判断和多个循环,可能的路径数目将会急剧增长,以致实现路径覆盖是几乎不可能的。
|
|