【软件工程】白盒测试

实验五 白盒测试


图:封面

开发语言及实现平台或实验环境

在 Windows 7 或 Windows 10 操作系统上,使用 C,C++,C#或 Java 语言 第 10 页 共 26 页
及对应的开发环境(IDE) 【实验目的】

  1. 熟悉掌握白盒测试的原理
  2. 掌握白盒测试过程,了解逻辑覆盖,独立路径测试、循环测试等白盒测
    试方法并能根据问题设计测试样例。

实验要求

  1. 要求学生能够理解白盒测试的相关概念和白盒测试的过程、方法。
  2. 具体为每一组,每组二——五人,根据实验题目编写出对应的 c 语言或
    c++语言程序,组间相互交换程序,按白盒测试的方法进行测试。

实验原理

对给定的模块,采用语句覆盖、判定覆盖、条件覆盖、判定\条件覆盖、 分组条件覆盖和路径覆盖的方法设计测试用例。

实验步骤

  1. 预习相关课堂内容,了解测试对象
  2. 编写实验材料源代码,画出程序流程图。
  3. 根据对应的实验题目,设计逻辑覆盖和路径覆盖的测试样例。 4. 执行测试样例,分析测试结果。
  4. 填写试验报告。

实验材料

  1. 逻辑覆盖根据下述题目,给出语句覆盖、判定覆盖、条件覆盖、判定\条件覆盖、
    分组条件覆盖和路径覆盖的测试用例并执行测试。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void DoWork(int x, int y, int z) {
    int k=0,j=0;
    if ((x>3)&&(z<10)) {
    k=k* y-1;
    j=sqrt(k);
    }
    if ((x==4)‖(y>5)) {
    j=x*y+10;
    j=j%3;
    }
    }
  2. N-S 流程图测试用例设计和执行
    编写一元二次方程( ax2+bx+c=0)算法,设计路径测试用例并执行测
    试。
  3. 基本路径测试用例设计和执行 编写对有序表进行折半查找的算法,计算圈复杂度,设计测试用例并
    执行独立路径测试。

实验代码

实验材料一

1
2
3
4
5
6
7
8
9
10
11
void DoWork(int x, int y, int z) {
int k=0,j=0;
if ((x>3)&&(z<10)) {
k=k* y-1;
j=sqrt(k);
}
if ((x==4)‖(y>5)) {
j = x*y+10;
j = j%3;
}
}

实验材料二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package procs;
import java.util.Scanner;//导入java.util包下的Scanner类


public class UnitaryQuadraticEquation {

public int argsA = 0;
public int argsB = 0;
public int argsC = 0;

public void inputCoefficient(UnitaryQuadraticEquation equation){
int argsA = 0;
int argsB = 0;
int argsC = 0;
System.out.print("======求 ax^2+bx+c=0 的根======"+"\n");
Scanner scanner = new Scanner(System.in);
do {
System.out.println("请输入a的值(a!=0):");
argsA = scanner.nextInt();
} while (argsA == 0);
equation.argsA = argsA;
System.out.println("请输入b的值:");

argsB = scanner.nextInt();
equation.argsB = argsB;
System.out.println("请输入c的值:");

argsC = scanner.nextInt();
equation.argsC = argsC;

}

public void calculateRoot(UnitaryQuadraticEquation equation){

//运用求根公式,并且Math.sqrt()为开平方根
double rootX1 = ((-equation.argsB + Math.sqrt(equation.argsB * equation.argsB
- 4 * equation.argsA * equation.argsC)) / (2 * equation.argsA));

//运用求根公式,并且Math.sqrt()为开平方根
double rootX2 = ((-equation.argsB - Math.sqrt(equation.argsB * equation.argsB
- 4 * equation.argsA * equation.argsC)) / (2 * equation.argsA));

// 第一个根X1
System.out.println("x1 = " + rootX1);
// 第一个根X2
System.out.println("x2 = " + rootX2);
}

public static void main(String[] args) {
UnitaryQuadraticEquation equation = new UnitaryQuadraticEquation();
equation.inputCoefficient(equation);
equation.calculateRoot(equation);

}

}

实验材料三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

package procs;


import java.util.Scanner;

public class BinarySearch {

/**
* 对有序表对折半查找
* @param orderlyTable 有序表(由小到大排列)
* @param key 要查找的关键字
* @return 返回要查找的关键字下标,若没有查找到则返回-1
*/
private static int BinarySearch(int[] orderlyTable, int key) {
int low, high, mid;
low = 0;
high = orderlyTable.length - 1;
while (low <= high) {
mid = (low + high) / 2;
if (key < orderlyTable[mid]) {
high = mid - 1;
} else if (key > orderlyTable[mid]) {
low = mid + 1;
} else
return mid;
}
return -1;
}

public static void main(String[] args) {
int key = 0;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查找的关键词:");
key = scanner.nextInt();


// 有序表
int[] orderlyTable = { 1, 2, 3, 4, 5, 6 };
// 调用BinarySearch方法计算关键词下标
int index = BinarySearch(orderlyTable, key);
System.out.println("关键词的下标是(-1表示未找到):" + index);
}

}

测试用例及设计

实验材料1:逻辑覆盖

1.语句覆盖
由于语句覆盖至要求每个语句执行一次即可,因此设计如下测试用例

用例ID X Y Z K
1 4 6 5 5

2.判定覆盖

判定覆盖是在语句覆盖的基础上,使得程序中的每个判定分值都覆盖,因此设计如下用例

用例ID X Y Z K
1 4 6 5 5
2 2 2 2 5

3.条件覆盖

在语句覆盖的基础上,使得程序中的每个条件(原子条件)都能获得可能的结果,因此设计如下用例

用例ID X Y Z K
1 4 5 5 5

4.判定条件覆盖

判定/条件覆盖是使得判定的每个条件都取到可能的值(即满足判定覆盖),也使得条件满足每个可能的结果(即满足条件覆盖)因此设计如下用例

用例ID X Y Z K
1 4 6 5 5

5.条件组合覆盖

条件组合覆盖是指设计足够多的测试用例,使得每个判定中的条件的各种可能组合都至少出现一次。

可能的条件组合:

    1. x>3, z<10, x=4, y>5
    1. x>3, z>=10, x=4, y>5
    1. x>3, z<10, x!=4, y>5
    1. x>3, z>=10, x!=4, y>5
    1. x>3, z<10, x=4, y<=5
    1. x>3, z>=10, x=4, y<=5
    1. x>3, z>=10, x!=4, y<=5
  • ….

相应的测试用例为:

用例ID X Y Z K
1 4 6 5 5
2 4 6 12 5
3 5 6 5 5
4 5 6 12 5
5 4 5 5 5
6 4 5 12 5
7 5 5 12 5

6.路径覆盖测试

路径覆盖测试是指设计足够多的测试数据,使得程序中的每一条可行路径(即从开始到结束的一条程序流)都至少执行一次。

路径有:

P1(FF)

P2(FT)

P3(TF)

P4(TT)

用例ID X Y Z K 路径
1 2 5 12 5 P1
2 2 6 5 5 P2
3 5 2 5 5 P3
4 4 6 6 5 P4

如上表的测试用例,使得程序中的每一条可行路径都执行了一次。

实验材料2:N-S 流程图测试

N-S流程图可用于测算最小测试用例,根据所写的实验代码,绘制N-S图:

  1. P1: a是否不等于0

  2. a: 输入的argsA有效

  3. b: 再次输入argsA

  4. c: 输入argsB

  5. d: 输入argsC

  6. e: 计算root1(第一个根)

  7. f: 计算root2(第二个根)

用例ID 条件 路径
1 P1 = True acdef
2 P1 = False bcdef

实验材料3:基本(独立)路径测试

基本(独立)路径测试是在程序控制流图的基础上,分析控制构造的环路复杂性,导出独立可执行路径集合,设置测试用例的方法。是路径覆盖测试的一种改进,它把覆盖的路径数压缩到一定限度内,程序中的循环体最多执行一次。

独立路径测试步骤是:

  1. 画出控制流程图(拓扑结构-流图)
  2. 计算流图G的环路复杂性V(G)
  3. 确定只包含独立路径的基本路径集
  4. 设计测试用例

以下为针对实验材料3到路径路径测试用例设计:

  1. 画出控制流程图 node0: low = 0; high = oderlyTable.length-1; node1: low <= high node2: mid = (low + high) / 2 node3: key < orderlyTable[mid] node4: high = mid - 1 node5: key > orderlyTable[mid] node6: low = mid + 1 node7: return mid node8: return -1
  2. 计算环路复杂性

V(G) = e - n +1 = 10-9+1 = 2
判定节点数为1, 加1,得2,验证正确

  1. 基本路径集

path1: 1-8
path2: 1-2-3-4-1-2-3-7
path3: 1-2-3-5-6-1-2-3-7
path4: 1-2-3-7

  1. 设计测试用例
用例ID orderlyTable Key 满足路径
1 [] 0 Path1
2 [1, 2, 3, 4, 5] 2 Path2
3 [1, 2, 3, 4, 5] 4 Path3
4 [1, 2, 3, 4, 5] 3 Path4

测试代码及结果分析

实验材料1: 逻辑覆盖

  1. 测试代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    package exps;

    public class DoWorkTesting_fifth {

    /**
    * DoWork的驱动函数
    * @param x
    * @param y
    * @param z
    * @param k
    * @return
    */
    public double doWork(int x, int y, int z , int k) {
    double j = 0;

    if ((x > 3) && (z < 10)) {
    k = k * y - 1;
    j = Math.sqrt(k);
    }
    if ((x == 4) || (y > 5)) {
    j = x * y + 10;
    j = j % 3;
    }
    return j;
    }



    public static void main(String[] args) {
    DoWorkTesting_fifth doWork = new DoWorkTesting_fifth();
    double tempJ = 0.00f;
    System.out.println("======语句覆盖======");
    tempJ = doWork.doWork(4, 6, 5, 5);
    System.out.println(tempJ);

    System.out.println("======判定覆盖======");
    tempJ = doWork.doWork(4, 6, 5, 5);
    System.out.println(tempJ);
    tempJ = doWork.doWork(2,2, 2, 5);
    System.out.println(tempJ);

    System.out.println("======条件覆盖======");
    tempJ = doWork.doWork(4, 5,5 ,5);
    System.out.println(tempJ);

    System.out.println("======判定条件覆盖======");
    tempJ = doWork.doWork(4, 6, 5, 5);
    System.out.println(tempJ);

    System.out.println("======条件组合覆盖======");
    System.out.println("...");

    System.out.println("======路径覆盖======");
    tempJ = doWork.doWork(2, 5, 12, 5);
    System.out.println(tempJ);
    tempJ = doWork.doWork(2, 6, 5, 5);
    System.out.println(tempJ);
    tempJ = doWork.doWork(5, 2, 5, 5);
    System.out.println(tempJ);
    tempJ = doWork.doWork(4, 6, 6, 5);
    System.out.println(tempJ);

    }
    }
  2. 结果分析

符合实验预期。

实验材料2:N-S流程图测试

  1. 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package exps;

import procs.UnitaryQuadraticEquation;

public class UnitaryQuadraticEquationTesting_fifth {
public static void main(String[] args) {
UnitaryQuadraticEquation equation = new UnitaryQuadraticEquation();

System.out.println("======Path 1======");
equation.argsA = 2;
equation.argsB = 3;
equation.argsC = 1;
equation.calculateRoot(equation);

System.out.println("======Path 2======");
equation.argsA = 0;
equation.argsB = 3;
equation.argsC = 1;
equation.calculateRoot(equation);
}
}
  1. 实验结果

符合实验预期。

实验材料3:独立路径测试

  1. 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package exps;

import procs.BinarySearch;

public class BinarySearchTesting_fifth {

public static void main(String[] args) {
BinarySearch binarySearch = new procs.BinarySearch();
int key = 0;

System.out.println("======Path 1======");
key = 0;
// 有序表
int[] orderlyTable_path1 = {};
// 调用BinarySearch方法计算关键词下标
int index = binarySearch.binarySearch(orderlyTable_path1, key);
System.out.println("关键词的下标是(-1表示未找到):" + index);

System.out.println("======Path 2======");
key = 2;
// 有序表
int[] orderlyTable = { 1, 2, 3, 4, 5};
// 调用BinarySearch方法计算关键词下标
index = binarySearch.binarySearch(orderlyTable, key);
System.out.println("关键词的下标是(-1表示未找到):" + index);

System.out.println("======Path 3======");
key = 4;
// 有序表, Path2中已定义

// 调用BinarySearch方法计算关键词下标
index = binarySearch.binarySearch(orderlyTable, key);
System.out.println("关键词的下标是(-1表示未找到):" + index);


System.out.println("======Path 4======");
key = 3;
// 有序表, Path2中已定义

// 调用BinarySearch方法计算关键词下标
index = binarySearch.binarySearch(orderlyTable, key);
System.out.println("关键词的下标是(-1表示未找到):" + index);
}
}
  1. 测试结果
结果符合预期。

实验总结

白盒一般的测试的步骤是什么?

  1. 测试计划阶段:根据需求说明书,制定测试进度

  2. 测试设计阶段:依据程序设计说明书,按照一定规范化的方法进行软件结构划分和设计测试用例

  3. 测试执行阶段:输入测试用例,得到测试结果

  4. 测试总结阶段:对比测试的结果和代码的预期结果,分析错误原因,找到并解决错误

白盒测试的测试用例设计有哪些方法?

  1. 逻辑覆盖测试

  2. 独立路径测试

  3. 循环测试

  4. 面对对象的白盒测试

  5. 域测试

  6. 符号测试

  7. Z路径覆盖

比较白盒、黑盒测试优缺点

白盒测试的优点:

对于黑盒测试:

  1. 优点
    1)从产品功能角度测试,可以最大限度的满足用户的需求
    2)相同的动作可以重复执行,最枯燥的部分可由机器完成
    3)依据测试用例有针对性地寻找问题,定位更加准确,容易生成测试数据
    4)可将测试直接和程序/系统要完成的操作相关联

  2. 缺点
    1)不能对程序代码进行测试
    2)如果规格说明设计错误,很难发现
    3)测试不能充分地进行
    4)测试结果的准确性取决于测试用例的设计
    5)自动化测试的复用性较低

 对于白盒测试 :

  1. 优点:
    帮助软件测试人员增大代码的覆盖率。 提供代码的质量,发现代码中隐藏的问题。

  2. 缺点 :
    1) 程序运行会有很多不同的路径,不可能测试所有的运行路径
    2) 测试基于代码,不能知道设计是否正确,可能会漏掉一些功能需求
    3) 系统庞大时,测试开销会非常大