软件测试–白盒测试
前言
黑盒测试和白盒测试是软件测试中最常用的手段,之前介绍的黑盒测试不关注软件产品如何实现,只关注其功能。 而白盒测试主要关注软件系统内部结构和工作原理。
黑白盒对比如下:
一、白盒测试
白盒测试就像是一个大盒子(想象成是一个软件或游戏),而我们知道这个盒子里面的所有东西是怎么摆放和工作的(就像我们知道软件里的代码是怎么写的)。我们的任务就是要打开这个盒子(查看代码),检查里面的每个部分是否都正常工作。
二、白盒测试方法
白盒测试也有多种方法,如代码检查法、静态结构分析法、程序插桩技术、逻辑覆盖法和基本路径测试等。
1.代码检查法
简单来说就是:直接检查代码,查找编码错误、逻辑错误、设计错误等问题。
具体点来说就是:它主要检查代码和设计的一致性,代码对标准的遵循,可读性,代码逻辑表达正确性,代码结构合理性等方面;发现程序中不安全、不明确和模糊部分,找出程序中不可移植部分;发现违背程序编写风格问题。其中包括变量检查、命名和类型审查、程序逻辑审查、程序语法检查和程序结构检查等内容。
在实际使用中,代码检查法能快速找到缺陷,发现30%到70%的逻辑设计和编码缺陷,而且代码检查法看到的是问题本身而非征兆。但是代码检查法非常耗费时间,并且需要经验和知识的积累。
2. 静态结构分析法
简单来说:无需执行程序,仅通过分析代码的结构、控制流、数据流等,来评估代码的质量。
具体而言:静态结构分析是一种对代码机械性的、程式化的特性进行分析的方法。在静态结构分析中,测试者通过使用测试工具分析程序源代码的系统结构、数据接口、内部控制逻辑等内部结构,生成函数调用关系图、模块控制流图、内部文件调用关系图、子程序表、宏和函数参数表等各类图形图表,可以清晰地标识整个软件系统的组成结构,使其便于阅读和理解,然后可以通过分析这些图表,检查软件有没有存在缺陷或错误。包括控制流分析、数据流分析、信息流分析、接口分析、表达式分析等。
3. 程序插桩技术
简单来说,程序插桩技术是借助往被测程序中插入操作来实现测试目的的方法,即向源程序中添加一些语句,实现对程序语句的执行、变量的变化等情况进行检查。
例如想要了解一个程序在某次运行中所有可执行语句被覆盖的情况,或是每个语句的实际执行次数,就可以利用程序插桩技术。
// 原始代码
public class HelloWorld {
public static void main(String[] args) {
sayHello();
sayHello();
sayHello();
}
public static void sayHello() {
System.out.println("Hello, World!");
}
}
插桩后的代码
为了使用程序插桩技术来记录sayHello方法的调用次数,我们可以在这个方法中添加一个静态变量来计数,并在每次调用时更新这个变量。这里就是我们的插桩:
public class HelloWorld {
// 插桩:添加一个静态变量来记录sayHello方法的调用次数
private static int callCount = 0;
public static void main(String[] args) {
sayHello();
sayHello();
sayHello();
// 输出调用次数(可选)
System.out.println("Method sayHello was called " + callCount + " times.");
}
public static void sayHello() {
// 插桩:在方法开始处增加调用次数的计数
callCount++;
System.out.println("Hello, World!");
}
}
4. 逻辑覆盖法(掌握)
逻辑覆盖法以程序内在的逻辑结构为基础,根据程序的流程图设计测试用例。根据覆盖的目标不同,又可分为语句覆盖、分支覆盖、条件覆盖、分支—条件覆盖、条件组合覆盖和路径覆盖。
- 语句覆盖:确保程序中的每一条语句至少被执行一次。
- 分支覆盖:确保程序中每一个判定的每一个分支(取真分支和取假分支)至少被执行一次。
- 条件覆盖:确保程序中每一个判定的每一个条件应取到各种可能的值。
- 分支—条件覆盖:同时满足判定覆盖和条件覆盖的标准。
- 条件组合覆盖:确保程序中每一个判定中各条件的每一种组合至少出现一次。
- 条件组合覆盖:确保每一个判断的所有可能结果都出现过,每一个判断中所有条件的所有可能结果都出现过,每一个进入点及结束点都执行过,判断中每一个条件都可以独立的影响判断的结果。
举个例子:
案例一:
假设我们有一个简单的函数,它根据输入的数字判断其正负或零:
def number_classification(n):
if n > 0:
return "Positive"
elif n == 0:
return "Zero"
else:
return "Negative"
4.1 语句覆盖测试
确保每个语句至少执行一次。
测试用例:
输入:1(执行if块)
输入:0(执行elif块)
输入:-1(执行else块)
4.2 分支覆盖测试
确保每个分支(真/假)至少执行一次。
测试用例:
输入:1(if条件为真)
输入:-1(if条件为假,else条件为真)
注意:这里我们不需要单独测试n == 0的情况,因为elif是if条件为假时才会考虑的分支。
4.3 条件覆盖法
确保每个条件(在逻辑表达式中)的每个可能结果至少出现一次。
测试用例:
输入:1(n > 0为真)
输入:0(n > 0为假,n = = 0为真)
输入:-1(n > 0为假,n = = 0为假)
4.4 分支-条件覆盖
确保每个条件在每个分支中至少有一次取“真”值和一次取“假”值的机会。
测试用例:
输入:1(n > 0为真,n = = 0为假)
输入:0(n > 0为假,n = = 0为真)
输入:-1(n > 0为假,n = = 0为假)
注意:这些测试用例与条件覆盖的测试用例相同,因为在这个例子中,每个条件只在一个分支中评估。
4.5 条件组合覆盖
确保每个条件的所有可能组合至少出现一次。
对于此函数,只有一个if语句包含两个条件(n > 0和n == 0),但它们是互斥的(不可能同时为真)。
因此,条件组合覆盖的测试用例与分支-条件覆盖的测试用例相同。
5. 基本路径法
在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例的方法。
案例二
def calculate_x(a, b, x):
if a > 0 and b > 0:
if a > b:
x = x / a
else:
x = x / b
else:
x = a + b
x = x * (a + b)
return x
- 语句覆盖(Statement Coverage):确保每个语句都至少执行一次。
测试用例:
a = 1, b = 2, x = 3(执行 a > b 为假的路径)
a = 3, b = 2, x = 3(执行 a > b 为真的路径)
a = -1, b = -2, x = 3(执行 else 路径)
- 分支覆盖(Branch Coverage):确保每个分支(真/假)都至少执行一次。
测试用例:
a = 1, b = 2, x = 3(a > 0 and b > 0 为真,但 a > b 为假)
a = 3, b = 2, x = 3(a > 0 and b > 0 为真,且 a > b 为真)
a = -1, b = -2, x = 3(a > 0 and b > 0 为假)
- 条件覆盖(Condition Coverage):确保每个条件的所有可能结果都至少执行一次。
测试用例:
a = 1, b = 2, x = 3(a > 0 为真,b > 0 为真,a > b 为假)
a = 3, b = 2, x = 3(a > 0 为真,b > 0 为真,a > b 为真)
a = -1, b = 2, x = 3(a > 0 为假,因此不评估 b > 0 和 a > b)
a = 2, b = -1, x = 3(a > 0 为真,b > 0 为假,因此不评估 a > b)
- 分支-条件覆盖(Branch-Condition Coverage):确保每个条件的所有可能结果在每个分支中都至少执行一次。
测试用例与条件覆盖相同,因为它们已经覆盖了所有分支和条件。
- 条件组合覆盖(Multiple Condition Coverage 或 Condition Combination Coverage):确保每个条件的所有可能组合都至少执行一次。
测试用例与条件覆盖相同,因为在这个例子中,a > 0 和 b > 0 的所有可能组合(真真、真假、假真、假假)都已经在条件覆盖的测试用例中被覆盖了。
- 路径覆盖(Path Coverage):确保所有可能的执行路径都至少执行一次。
测试用例与分支覆盖的测试用例相同,因为在这个例子中,没有额外的路径需要被覆盖。
三、 白盒测试方法的选择
此外,白盒测试还有静态质量度量、域测试、Z路径覆盖等方法,本书不再展开叙述。白盒测试的每种测试方法都有各自的优点和不足,需要测试人员根据实际软件特点、实际测试目标和测试阶段选择合适的方法设计测试用例,这样能有效地发现软件错误,提高测试效率和测试覆盖率。以下是选择方法的几条经验:
从过程的观点考虑测试,在软件工程环境中的测试过程,实际上是顺序进行的4个步骤的序列。最开始,着重测试每个单独的模块,以确保它作为一个单元来说功能是正确的,这种测试称为单元测试。单元测试大量使用白盒测试技术,检查模块控制结构中的特定路径,以确保做到完全覆盖并发现最大数量的错误。
接下来,必须把模块装配(即集成)在一起形成完整的软件包,在装配的同时进行测试,因此称为集成测试。集成测试同时解决程序验证和程序构造这两个问题。在集成过程中最常用的是黑盒测试用例设计技术。当然,为了保证覆盖主要的控制路径,也可能使用一定数量的白盒测试。在软件集成完成之后,还需要进行一系列高级测试。必须测试在需求分析阶段确定下来的确认标准,确认测试是对软件满足所有功能的、行为的和性能需求的最终保证。在确认测试过程中仅使用黑盒测试技术。
软件一旦经过确认之后,就必须和其他系统元素(如硬件、人员、数据库)结合在一起。系统测试的任务是,验证所有系统元素都能正常配合,从而可以完成整个系统的功能,并能达到预期的性能。验收测试以用户测试为主,分为a测试和b测试。a测试指的是由用户、测试人员、开发人员等共同参与的内部测试,而b测试指的是完全交给最终用户的测试。