目录
(一)什么是白盒测试
白盒测试方法根据模块内部结构,基于程序内部逻辑结构,针对程序语句、路径、变量状态等来进行测试。 单元测试主要采用白盒测试方法,辅以黑盒测试方法。白盒测试方法应用于代码评审、单元程序之中,而黑盒测试方法则应用于模块、组件等大单元的功能测试之中。
白盒测试关注的对象
1、源代码
措施:阅读源代码,检验代码的规范性,并对照函数功能查找代码的逻辑缺陷、内存管理缺陷、数据定义和使用缺陷等。
2、程序结构
措施:使用与程序设计相关的图表,找到程序设计的缺陷,或评价程序的执行效率。
白盒测试方法分类
(二)控制流分析技术
常见的程序结构:
判定结点导致结构的复杂
控制流分析的内容
控制程序执行流程发生变化的主要因素是什么?
判定结点
关注判定节点固有的复杂性
焦点:判定表达式
方法:逻辑覆盖测试
关注判定结构与循环结构对执行路径产生的影响
焦点:路径
方法:独立路径测试
关注循环结构本身的复杂性
焦点:循环体
方法:基于数据的静态分析
(三)白盒测试用例设计及应用
逻辑覆盖法
逻辑覆盖是通过对程序逻辑结构的遍历实现对程序的覆盖,它是一系列测试过程的总称,这组测试过程逐渐实现越来越完整的通路测试。逻辑覆盖标准包括以下不同的覆盖标准:
- 语句覆盖(Statement Coverage,SC)
- 判定覆盖(Decision Coverage,DC)
- 条件覆盖(Condition Coverage,CC)
- 条件判定组合覆盖(Condition/Decision Coverage,DC)
- 多条件覆盖(Multiple Condition Coverage,MCC)
- 修正条件判定覆盖(modified condition decision coverage,MCDC)
语句覆盖
语句覆盖,又称行覆盖(LineCoverage)、段覆盖(SegmentCoverage)、基本块覆盖(BasicBlockCoverage),这是最常用也是最常见的一种覆盖方式。其基本思想是设计若干个测试用例,运行被测程序,使程序中每一条可执行语句至少应该执行一次。
语句覆盖-案例
单元设计要求:设计一个方法,输入两个整型参数x,y,当x小于5或者y=5时将x和y的和作为结果返回;否则,将x和y的商作为结果返回。
单元实现
public class MyClass {
public int computing(int x, int y) {
int result;
if (x < 5 && y == 5) {
result = x + y;
} else {
result= x / y;
}
return result;
} }
序号 | X | y | 预期结果 | X<5 | Y==5 | x < 5 && y == 5 | 路径 |
1 | 2 | 5 | 7 | T | T | T | |
2 | 6 | 6 | 1 | F | F | F |
判定覆盖
希望通过设计足够多的测试用例,使得程序中的每个判定至少都获得一次“真”值和“假”值, 也就是使程序中的每个取“真”分支和取“假”分支至少均经历一次,这种设计测试用例的方法称为判定覆盖,也称为“分支覆盖”。
判定覆盖-案例
public class MyClass {
public int computing(int x, int y) {
int result;
if (x < 5 || y == 5) {
result = x + y;
} else {
result= x / y;
}
return result;
} }
序号 | x | y | 预期结果 | x<5 | y==5 | x < 5 || y == 5 | 路径 |
1 | 2 | 6 | 8 | T | F | T | |
2 | 6 | 6 | 1 | F | F | F |
条件覆盖
通过设计足够多的测试用例,使得程序中每个判定包含的每个条件的可能取值(真/假)都至少出现一次。这种设计测试用例的方法称为条件覆盖。
public class MyClass {
public int computing(int x, int y) {
int result;
if (x < 5 || y == 5) {
result = x + y;
} else {
result= x / y;
}
return result;
} }
序号 | x | y | 预期结果 | x<5 | y==5 | x < 5 || y == 5 | 路径 |
1 | 2 | 1 | 3 | T | F | T | |
2 | 6 | 5 | 1 | F | T | T |
这个测试用例集满足条件覆盖的要求,但是不满足判定覆盖的要求
判定/条件覆盖
通过设计足够多的测试用例,使得程序中每个判定包含的每个条件的所有情况(真/假)至少出现一次,并且每个判定本身的判定结果(真/假)也至少出现一次。这种设计测试用例的方法称为判定/条件覆盖。 满足判定/条件覆盖的测试用例集一定同时满足判定覆盖和条件覆盖。
序号 | x | y | 预期结果 | x<5 | y==5 | x < 5 || y == 5 | 路径 |
1 | 2 | 1 | 3 | T | F | T | |
2 | 6 | 5 | 1 | F | T | T | |
3 | 6 | 1 | 1 | F | F | F |
组合覆盖
通过设计足够多的测试用例,使得程序中每个判定的所有可能的条件取值组合都至少出现一次。这种设计测试用例的方法称为组合覆盖。 满足组合覆盖的测试用例集一定满足判定覆盖、条件覆盖和判定/条件覆盖。
public class MyClass {
public int computing(int x, int y) {
int result;
if (x < 5 || y == 5) {
result = x + y;
} else {
result= x / y;
}
return result;
} }
序号 | x | y | 预期结果 | x<5 | y==5 | x < 5 || y == 5 | 路径 |
1 | 2 | 1 | 3 | T | F | T | |
2 | 6 | 5 | 1 | F | T | T | |
3 | 6 | 1 | 1 | F | F | F | |
4 | 1 | 5 | 0 | T | T | T |
基本路径测试法
通过设计足够多的测试用例,要求覆盖程序的基本路径集合中所有可能的路径。这种设计测试用例的方法称为基本路径覆盖。
程序的控制流图
控制流图的环路复杂性
程序的环路复杂性即McCabe复杂性度量,在进行程序的基本路径测试时,从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确保程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。 独立路径是指包括一组以前没有处理过的语句或条件的一条路径。从控制流图来看,一条独立路径是至少包含有一条在其他独立路径中从未有过的边的路径。(b)所示的控制流图中,一组独立的路径如下:
path1:1-11
path2:1-2-3-4-5-10-1-11
path3:1-2-3-6-8-9-10-1-11
path4:1-2-3-6-7-9-10-1-11
基本路径覆盖-测试用例设计步骤
(1)以详细的设计或源代码为基础,导出程序的控制流程图
(2)计算控制流图G的环路复杂性V(G)
V(G)=区域数
V(G)=判断节点数+1
V(G)=边的个数-节点个数+2
(3)导出独立路径
(4)设计测试用例,确保每条路径都被执行
基本路径覆盖-案例
将一个正整数分解为质因数的Java程序
int k=2;
String rs=n+"=";
while(k<=n){
if(k==n){
rs=rs+n;
break;
}else{
if(n%k==0){
rs=rs+k+"*";
n=n/k;
}else{
k++;
}}}
return rs;
(1)画出程序控制流图
(2)计算环形复杂度:
V(G)=3
(3)找出一组独立路径(基本路径集合):
路径1:1-2-3-4
路径2:1-2-3-5-6-8-2-3-4
路径3:1-2-3-5-7-8-2-3-4
(4)根据基本路径设计测试用例,覆盖基本路径集合中的所有路径