静态的白盒测试方法有桌面检查、代码审查、代码走查和代码扫描工具。
动态的白盒测试方法有逻辑覆盖法和基本路径测试法。
逻辑覆盖法有语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖和路径覆盖。
例1
int a=0;
public class E01(int x,int y,int m){
if(x>&&y>0){
a=x+y;//语句块1
}
else{
a=x-y;//语句块2
}
if(m<0){
a=m;//语句块3
}
return a;//语句块4
}
将上述程序画出流程图,如下:
语句覆盖,就是设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。度量被测代码中每个可执行语句是否被执行到了。
语句覆盖标准最弱,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。
语句覆盖率=可执行的语句总数/被评价到的语句数量 x 100%
将例1进行语句覆盖,写出测试用例如下:
数据 | 语句 |
---|---|
x=1,y=1,m=2 | 1,4 |
x=-1,y=-1,m=-2 | 2,3,4 |
若将语句块1改为if(x>0||y>0)
,语句覆盖还是覆盖成功,不符合测试需求。因为语句覆盖不能准确的判断运算中的逻辑关系错误。(语句覆盖的缺点)
定义:判定覆盖使设计的测试用例保证程序中每个判断的每个取值分支(ture or false)至少经历一次。
【优点】:判定覆盖具有比语句覆盖更强的测试能力。同样分支(判定)覆盖也具有和语句覆盖一样的简单性,无须细分每个判定就可以得到测试用例。
【缺点】:往往大部分的分支(判定)语句是由多个逻辑条件组合而成,若仅仅判断其整个最终结果,而忽略每个条件的取值情况,必然会遗漏部分测试路径。判定覆盖仍是弱的逻辑覆盖。
将例1进行判定覆盖,写出测试用例如下:
P1为“x>0&&y>0”判定,P2为“m<0”判定
P1 | P2 | 用例 |
---|---|---|
T | F | x=1,y=1,m=1 |
F | T | x=-1,y=-1,m=1 |
F | F | x=-1,y=-1,m=-1 |
T | T | x=1,y=1,m=-1 |
只要满足了判定覆盖标准就一定满足语句覆盖标准。
判定覆盖会忽略条件中取或(or)的情况。
若将语句块1改为if(x>0||y>0)
,判定覆盖还是覆盖成功,不符合测试需求。
定义:设计足够多的测试用例,运行被测程序,使得每一判定语句中每个逻辑条件的可能取值至少满足一次。
回头看例1的流程图,判定条件定义如下:
x>0&&y>0判定记为:P1
m<0判定记为:P2
x>0记为:C1
y>0记为:C2
m<0记为:C3
测试用例设计如下:
C1 | C2 | C3 | P1 | P2 | 用例 | 路径 |
---|---|---|---|---|---|---|
T | F | T | F | T | x=1,y=-1,m=-1 | acd |
F | T | F | F | F | x=-1,y=1,m=-1 | ace |
条件覆盖比判定覆盖,增加了对判定中所有条件的测试。
但条件覆盖并不能保证判定覆盖。例如:P1为真,没有覆盖。
定义:设计测试用例,使得被测试程序中的每个判断本身的判定结果(真假)至少满足一次,同时,每个逻辑条件的可能值(真假)也至少被满足一次。即同时满足100%判定覆盖和100%条件覆盖的标准。
判定条件覆盖率=每个判断本身的判定结果(真假)至少满足一次/判定结果的总数+条件结果的总数
例1代码中有2个判定,条件3个。所以,判定结果为2* 2(true,false)=4个,条件结果3*2(true,false)=6个。
设计测试用例执行3个判定结果,5个条件结果,判定条件覆盖率为:(3+5)/(4+6)=80%
将例1进行判定条件覆盖,写出测试用例如下:
C1 | C2 | C3 | P1 | P2 | 用例 | 路径 |
---|---|---|---|---|---|---|
T | T | F | T | F | x=1,y=1,m=1 | abe |
F | F | T | F | T | x=-1,y=-1,m=-1 | acd |
满足判定条件覆盖标准,一定能够满足条件覆盖、判定覆盖和语句覆盖。
判定条件覆盖会忽略条件中取或(or)的情况。
定义
判定中条件的各种组合都至少被执行一次。
特点
(1)满足条件组合覆盖的用例一定满足语句覆盖、条件覆盖、判定覆盖和判定覆盖。
(2)条件组合覆盖没有考虑各判定结果(真或假)组合情况,不满足路径覆盖
(3)条件组合数量大,设计测试用例的时间花费较多。
例1使用条件组合覆盖,测试用例设计如下:
C1 | C2 | C3 | P1 | P2 | 用例 | 路径 |
---|---|---|---|---|---|---|
T | T | T | T | T | x=1,y=1,m=-1 | abd |
T | F | T | F | T | x=1,y=-1,m=-1 | acd |
F | T | T | F | T | x=-1,y=1,m=-1 | acd |
F | F | T | F | T | x=-1,y=-1,m=-1 | acd |
T | T | F | T | F | x=1,y=1,m=1 | abe |
T | F | F | F | F | x=1, y=-1,m=1 | ace |
F | T | F | F | F | x=-1,y=1,m=1 | ace |
F | F | F | F | F | x=-1,y=-1,m=1 | ace |
定义
使程序的每条可能路径都至少执行一次。
特点
路径覆盖可以对程序进行彻底的测试,比前面五种覆盖面都广。
C1 | C2 | C3 | P1 | P2 | 用例 | 路径 |
---|---|---|---|---|---|---|
T | T | T | T | T | x=1,y=1,m=-1 | abd |
T | T | F | T | F | x=1,y=1,m=1 | abe |
T | F | T | F | T | x=1,y=-1,m=-1 | acd |
F | F | F | F | F | x=-1,y=-1,m=1 | ace |
定义
在程序控制流图的基础上,通过分析程序的环路复杂性,导出基本可执行路径集合,从而设计测试用例。
步骤
第一步,根据代码画出程序控制流图;
第二步,计算程序的环路复杂度;
第三步,导出可执行路径;
第四步,设计测试用例。
void Sort(int a,int b){
int x=0;
int y=0;
while(a-- >0){ //将此判断记为P1
if(0==b) //将此判断记为P2
x=y+2;break; //将此语句记为s1
else
if(1==b) //将此判断记为P3
x=y+10; //将此语句记为s2
else
x=y+20; //将此语句记为s3
}
}
第一步,控制流图,如下图:
第二步,计算程序环路复杂度
方法有三种:
流图中区域的数量对应于环型的复杂性。
给定流图G的圈复杂度V(G),定义为V(G)=E-N+2,E是流图中边的数量,N是流图中节点的数量。技巧:边数——数箭头,结点——数判断框和语句
边数10,结点8,所以V(G)=10-8+2。
给定流图G的圈复杂度V(G),定义为V(G)=P+1,P是上图中判定节点的数量。V(G)=3+1
用环路复杂度验证测试用例是否覆盖全了。
第三步,导出可执行路径
回头看例子的程序流程图,此例子可导出路径为:
路径1:P1-退出程序
路径2:P1-P2-S1-退出程序
路径3:P1-P2-P3-S2-退出P3-P1-退出程序
路径4:P1-P2-P3-S3-退出P3-P1-退出程序
第四步,设计测试用例
测试数据 | 覆盖路径 |
---|---|
a=0 | 路径1 |
a=1,b=0 | 路径2 |
a=1,b=1 | 路径3 |
a=1,b=2 | 路径4 |
白盒测试主要应用于单元测试阶段。白盒设计用例一般使用基本路径测试,重点模块使用多个覆盖率标准。