软件测试循环语句覆盖法
软件测试循环语句覆盖法
简单循环覆盖
循环是反复运行同一段代码的语法结构,是代码中常见的一种结构。在白盒测试中,循环结构的测试也是我们需要掌握的内容。循环结构测试主要的侧重点是验证循环结构的有效性,一般可以结合条件覆盖、基本路径覆盖以及黑盒测试方法中的等价类、边界值等方法来设计测试用例。
白盒测试:简单循环、串接循环、嵌套循环和非结构化循环
其中非结构化循环的可读性、可维护性和可测试性都很差,一般建议重新设计并调整为结构化的程序代码后再进行测试。
实验内容
测试对象是求任意一个10以内整数的阶乘,输入1 ~ 10的任意整数,输出该数字的阶乘数;输入不为 1 ~ 10 的整数时提示“请输入 1 ~ 10 的整数!
public static int getFactorial(Integer num) {
int result = 0;
if (num >= 1 && num <= 10){
result = 1;
int i = 1;
while (i < num){
result = result * i;
i++;
}
System.out.println(num + "的阶乘为:" + result);
}
else{
System.out.println("请输入1~10的整数!");
}
return result;
}
实验步骤
第 1 步:分析源代码,画出流程图。
第 2 步:设计测试用例。
循环测试的侧重点是测试循环结构的有效性,主要考虑循环的边界和运行界限执行循环体的情况,所以设计简单循环结构的测试用例主要需要考虑循环变量的 初始值、增量、最大值 ,以及边界取值的情况下代码处理是否正确。我们可以结合黑盒测试用例设计方法中的等价类边界值的方法来设计测试用例,即”如果输入/输出条件规定了值的个数,则用最大个数、最小个数、比最小个数少 1 ,比最大个数多 1 的值作为测试数据“。一般来说,简单循环的测试用例需要考虑下列几种情况(设最大循环次数为 n ):
(1)循环 0 次:测试跳过整个循环的场景;
(2)循环 1 次:目的是检查循环的初始值是否正确;
(3)循环 2 次:目的是检查多次循环是否正确;
(4)循环 m 次(其中 2 < m < n - 1):目的是检查多次循环是否正确,这里我们也可以用等价类的思想来理解,即:可以把大于 2 次、小于 n - 1 次看成是一个等价类,m 可以是这个范围中的任意一个值,根据等价类的思想,如果这个范围中的任意一个值是不会发现程序的问题,那么,我们可以认为这个等价类中所有的值都不会发现程序的问题;
(5)循环 n - 1 次:目的是检查边界值是否正确;
(6)循环 n 次:目的是检查边界值是否正确;
(7)循环 n + 1 次:目的是检查边界值是否正确。
这里读者可能会有疑问,一个循环的最大循环次数是 n ,我们要怎么让它循环 n + 1 次呢?这不是一个伪命题吗?通过对边界值方法的理解,我们可以知道,等于、大于、小于边界值的地方是最容易出现 bug 的,如,“差 1 错”,即不正确的多循环或者少循环了一次。在循环结构的测试中设计循环 n + 1次的测试用例,就是为了检查代码是否会出现多循环一次的错误。在实际的测试过程中,我们可以通过分析代码结构决定是否能设计出循环 n + 1次的测试用例。
案列:
循环次数 | 0 次 | 1 次 | 2 次 | m 次 | n-1 次 | n 次 | n+1 次 |
---|---|---|---|---|---|---|---|
测试用例( num 的值) | 0 | 1 | 2 | 5 | 9 | 10 | 11 |
转化为测试用例,如下表所示:
测试用例编号 | 输入 | 预期输出 |
---|---|---|
testcase_01 | 0 | result=0,输出:请输入1~10的整数! |
testcase_02 | 1 | result=1,输出:1的阶乘是1 |
testcase_03 | 2 | result=2,输出:2的阶乘是2 |
testcase_04 | 5 | result=120,输出:5的阶乘是120 |
testcase_05 | 9 | result=362880,输出:9的阶乘是362880 |
testcase_06 | 10 | result=3628800,输出:10的阶乘是3628800 |
testcase_07 | 11 | result=0,输出:请输入1~10的整数! |
第 3 步:执行测试用例。
白盒测试用例一般使用专门的测试工具(如:Junit)来执行,使用这些工具可以非常方便的编写测试用例、判断测试用例执行结果是否正确。在没有学习测试工具之前,我们先使用调用被测函数的方法来执行测试用例。具体执行方法为:
1)依次使用测试用例的输入值调用被测对象;
2)比较被测对象的实际返回值与测试用例的“预期输出”是否一致:如果一致,则测试用例执行通过;如果不一致,则测试用例执行失败。
具体的测试代码如下:
package test;
public class simpleTest {
// 执行测试用例
public static void main(String[] args) {
// 执行用例 testcase_01
if(getFactorial(0) == 0){
System.out.println("testcase_01执行通过\n");
}
else{
System.out.println("预期输出为:0 ");
System.out.println("testcase_01执行失败\n");
}
// 执行用例 testcase_02
if(getFactorial(1) == 1){
System.out.println("testcase_02执行通过\n");
}
else {
System.out.println("预期输出为:1 ");
System.out.println("testcase_02执行失败\n");
}
// 执行用例 testcase_03
if(getFactorial(2) == 2){
System.out.println("testcase_03执行通过\n");
}
else{
System.out.println("预期输出为:2 ");
System.out.println("testcase_03执行失败\n");
}
// 执行用例 testcase_04
if(getFactorial(5) == 120){
System.out.println("testcase_04执行通过\n");
}
else{
System.out.println("预期输出为:120 ");
System.out.println("testcase_04执行失败\n");
}
// 执行用例testcase_05
if(getFactorial(9) == 362880){
System.out.println("testcase_05执行通过\n");
}
else{
System.out.println("预期输出为:362880 ");
System.out.println("testcase_05执行失败\n");
}
// 执行用例testcase_06
if(getFactorial(10) == 3628800){
System.out.println("testcase_06执行通过\n");
}
else{
System.out.println("预期输出为:3628800 ");
System.out.println("testcase_06执行失败\n");
}
// 执行用例 testcase_07
if(getFactorial(11) == 0){
System.out.println("testcase_07执行通过\n");
}
else{
System.out.println("testcase_07执行失败\n");
}
}
从上图可以看出,七个测试用例有四个是执行失败的。分析这四个用例的实际输出和预期输出,我们可以发现:实际输出和预期输出相比,少乘了一个该数字本身,例如,测试用例 testcase_03 “ 2 的阶乘”的实际输出是 1 ,预期输出是 2 ,少乘了 2 ;测试用例 testcase_04 “ 5 的阶乘”的实际输出是 24 ,预期输出是 120 ,少乘了 5 。由此我们可以推断出,计算阶乘的 while 循环少循环了一次,即 while (i < num) 应该改为 while (i <= num) 。 。 修改代码后重新执行测试用例进行回归测试的结果如下,所有用例都执行通过:
实验总结
简单循环的测试重点是验证循环结构的有效性,主要考虑循环的边界和运行界限执行循环体的情况。对于最多为 n 次的简单循环,一般需要设计 跳过循环、循环 1 次、2 次,m 次(2<m<n-1)、n - 1 次、n 次、n + 1 次 的测试用例,重点测试循环变量的 初值、最大值、增量 以及退出循环的情况。如果循环的最大循环次数不确定,一般设计跳过循环、循环 1 次、2 次,m 次的测试用例即可。