第一部分 数学基础 2
第1章 测试概述 2
1.1 基本概念 2
1.2 测试用例 3
1.3 利用维恩图来理解软件测试 3
1.4 构造测试用例 4
1.4.1 基于规格说明的测试 5
1.4.2 基于代码的测试 5
1.4.3 两种测试方法的对比 6
1.5 故障的分类 7
1.6 测试的层次 8
1.7 习题 8
1.8 参考文献 8
第2章 程序示例 9
2.1 通用伪代码 9
2.2 角形问题 10
2.2.1 问题描述 10
2.2.2 三角形问题的讨论 11
2.2.3 三角形问题的经典实现 11
2.2.4 三角形问题的结构化实现 14
2.3 NextDate日期函数 15
2.3.1 问题描述 15
2.3.2 NextDate函数的讨论 16
2.3.3 NextDate函数的实现 16
2.4 佣金问题 18
2.4.1 问题描述 18
2.4.2 佣金问题的讨论 19
2.4.3 佣金问题的实现 19
2.5 SATM系统 20
2.5.1 问题描述 20
2.5.2 SATM系统的讨论 21
2.6 货币兑换计算器 22
2.7 雨刷控制器 22
2.8 车库门遥控开关 22
2.9 习题 23
2.10 参考文献 24
第3章 面向测试人员的离散数学 25
3.1 集合论 25
3.1.1 集合的成员关系 25
3.1.2 集合的定义方法 25
3.1.3 空集 26
3.1.4 集合的维恩图 26
3.1.5 集合运算 27
3.1.6 集合关系 28
3.1.7 集合划分 29
3.1.8 集合恒等 29
3.2 函数 30
3.2.1 定义域与值域 30
3.2.2 函数类型 30
3.2.3 函数复合 31
3.3 关系 32
3.3.1 集合之间的关系 32
3.3.2 单个集合上的关系 33
3.4 命题逻辑 34
3.4.1 逻辑运算符 34
3.4.2 逻辑表达式 35
3.4.3 逻辑等价 35
3.5 概率论 36
3.6 习题 37
3.7 参考文献 37
第4章 面向测试人员的图论 38
4.1 图 38
4.1.1 节点的度 38
4.1.2 关联矩阵 39
4.1.3 邻接矩阵 39
4.1.4 路径 40
4.1.5 连通性 40
4.1.6 压缩图 41
4.1.7 圈数 41
4.2 有向图 41
4.2.1 入度与出度 42
4.2.2 节点类型 42
4.2.3 有向图的邻接矩阵 43
4.2.4 路径与半路径 43
4.2.5 可达矩阵 44
4.2.6 n连通性 44
4.2.7 强分图 44
4.3 软件测试中常用的图 45
4.3.1 程序图 45
4.3.2 有限状态机 46
4.3.3 Petri网 47
4.3.4 事件驱动Petri网 49
4.3.5 状态图 50
4.4 习题 52
4.5 参考文献 52
第二部分 单元测试 54
第5章 边界值测试 54
5.1 边界值分析 54
5.1.1 边界值分析的拓展 55
5.1.2 边界值分析的局限性 56
5.2 健壮性测试 56
5.3 最坏情况测试 57
5.4 特殊值测试 57
5.5 示例 58
5.5.1 三角形问题的测试用例 58
5.5.2 NextDate函数的测试用例 59
5.5.3 佣金问题的测试用例 60
5.6 随机测试 62
5.7 边界值测试的原则 63
5.8 习题 65
第6章 等价类测试 66
6.1 等价类 66
6.2 传统的等价类测试 66
6.3 改进的等价类测试 67
6.3.1 弱一般等价类测试 68
6.3.2 强一般等价类测试 68
6.3.3 弱健壮等价类测试 68
6.3.4 强健壮等价类测试 69
6.4 三角形问题的等价类测试用例 69
6.5 NextDate函数的等价类测试用例 71
6.6 佣金问题的等价类测试用例 73
6.7 边缘测试 75
6.8 原则与注意事项 75
6.9 习题 76
6.10 参考文献 76
第7章 基于决策表的测试 77
7.1 决策表 77
7.2 决策表使用技巧 77
7.3 三角形问题的测试用例 80
7.4 Next Date函数的测试用例 81
7.4.1 第一轮尝试 81
7.4.2 第二轮尝试 82
7.4.3 第三轮尝试 83
7.5 佣金问题的测试用例 85
7.6 因果关系图 85
7.7 原则与注意事项 86
7.8 习题 87
7.9 参考文献 87
第8章 路径测试 88
8.1 程序图 88
8.2 DD路径 90
8.3 测试覆盖指标 92
8.3.1 基于程序图的覆盖度量方法 92
8.3.2 E.F.Miller的覆盖度量方法 92
8.3.3 复合条件下的闭合路径 95
8.3.4 示例 96
8.3.5 测试覆盖分析器 99
8.4 基路径测试 99
8.4.1 McCabe的基路径方法 100
8.4.2 McCabe基路径方法的考虑 102
8.4.3 McCabe方法的基本复杂度 103
8.5 原则与注意事项 105
8.6 习题 105
8.7 参考文献 106
第9章 数据流测试 107
9.1 定义/使用测试 107
9.1.1 举例 108
9.1.2 stocks的定义使用路径 110
9.1.3 locks的定义使用路径 110
9.1.4 totalLocks的定义使用路径 113
9.1.5 sales的定义使用路径 113
9.1.6 commission的定义使用路径 115
9.1.7 定义使用路径的测试覆盖指标 115
9.1.8 面向对象编码的定义/使用测试 116
9.2 基于程序切片的测试 116
9.2.1 举例 118
9.2.2 风格与技术 122
9.2.3 切片拼接 123
9.3 程序切片工具 124
9.4 习题 125
9.5 参考文献 125
第10章 单元测试回顾 126
10.1 测试方法的摇摆 126
10.2 测试方法摇摆问题探索 128
10.3 用于评估测试方法的指标 131
10.4 重新修订的案例研究 133
10.4.1 基于规格说明的测试 133
10.4.2 基于代码的测试 136
10.5 指导方针 138
10.6 习题 139
10.7 参考文献 139
第三部分 超越单元测试 142
第11章 基于生命周期的测试 142
11.1 传统瀑布模型测试 142
11.1.1 瀑布模型测试 143
11.1.2 瀑布模型的优缺点 143
11.2 在迭代生命周期中测试 144
11.2.1 瀑布模型的变体 144
11.2.2 基于规格说明的生命周期模型 146
11.3 敏捷测试 147
11.3.1 极限编程 148
11.3.2 测试驱动开发 148
11.3.3 Scrum 149
11.4 敏捷模型驱动开发 150
11.4.1 敏捷模型驱动开发概述 150
11.4.2 模型驱动的敏捷开发 151
11.5 参考文献 151
第12章 基于模型的测试 152
12.1 基于模型测试 152
12.2 恰当的系统模型 152
12.2.1 Peterson构架 153
12.2.2 主流模型的表达能力 154
12.2.3 建模问题 154
12.2.4 选择恰当的模型 156
12.3 支持基于模型的测试的商用工具 156
12.4 参考文献 156
第13章 集成测试 157
13.1 基于功能分解的集成 157
13.1.1 自顶向下的集成 160
13.1.2 自底向上的集成 161
13.1.3 三明治集成 161
13.1.4 优点和缺点 162
13.2 基于调用图的集成 162
13.2.1 成对集成 163
13.2.2 相邻集成 164
13.2.3 优点和缺点 166
13.3 基于路径的集成 166
13.3.1 新概念与扩展概念 167
13.3.2 MM路径的复杂度 168
13.3.3 优点和缺点 168
13.4 示例:集成版NextDate 169
13.4.1 基于分解的集成 169
13.4.2 基于调用图的集成 170
13.4.3 基于MM路径的集成 172
13.5 结论和建议 174
13.6 习题 174
13.7 参考文献 175
第14章 系统测试 176
14.1 线索 176
14.1.1 线索存在的可能性 177
14.1.2 线索定义 177
14.2 需求说明的基本概念 178
14.2.1 数据 178
14.2.2 操作 179
14.2.3 设备 179
14.2.4 事件 180
14.2.5 线索 181
14.2.6 基本概念之间的关系 181
14.3 基于模型的线索 181
14.4 基于用例的线索 184
14.4.1 用例的层次 184
14.4.2 一个实用的测试执行系统 186
14.4.3 系统级的测试用例 187
14.4.4 用事件驱动Petri网来表述用例 188
14.4.5 用事件驱动Petri网来表述有限状态机 190
14.4.6 哪种视角最适用于系统测试 190
14.5 长用例与短用例 190
14.6 到底需要多少用例 193
14.6.1 关联到输入事件 193
14.6.2 关联到输出事件 194
14.6.3 关联到全部端口事件 194
14.6.4 关联到类 194
14.7 系统测试的覆盖性指标 194
14.7.1 基于模型系统测试的覆盖性 195
14.7.2 基于规格说明系统测试的覆盖性 195
14.8 系统测试的其他方法 196
14.8.1 性能分析 197
14.8.2 基于风险的测试 199
14.9 非功能性系统测试 200
14.9.1 压力测试的策略 200
14.9.2 利用数学的方法 201
14.10 原子系统功能测试示例 202
14.10.1 找出输入事件和输出事件 204
14.10.2 找出原子系统功能 205
14.10.3 修正原子系统功能 205
14.11 习题 206
14.12 参考文献 207
第15章 面向对象测试 208
15.1 面向对象测试的相关问题 208
15.1.1 面向对象测试的单元 208
15.1.2 合成与封装的含义 208
15.1.3 继承的含义 210
15.1.4 多态性的含义 211
15.1.5 面向对象测试的层次 211
15.1.6 面向对象软件的数据流测试 211
15.2 面向对象NextDate示例 211
15.2.1 CalendarUnit类 213
15.2.2 testIt类 213
15.2.3 Date类 213
15.2.4 Day类 214
15.2.5 Month类 214
15.2.6 Year类 215
15.3 面向对象的单元测试 216
15.3.1 以方法为单元的测试 216
15.3.2 以类为单元的测试 216
15.4 面向对象的集成测试 221
15.4.1 UML对集成测试的支持 221
15.4.2 面向对象软件的MM路径 223
15.4.3 面向对象数据流集成测试的框架 227
15.5 面向对象的系统测试 229
15.5.1 货币兑换计算器的UML描述 229
15.5.2 基于UML的系统测试 233
15.5.3 基于状态图的系统测试 235
15.6 习题 235
15.7 参考文献 235
第16章 软件复杂度 236
16.1 单元级复杂度 236
16.1.1 圈复杂度 236
16.1.2 计算复杂度 239
16.2 集成级复杂度 240
16.2.1 集成级圈复杂度 241
16.2.2 消息流量复杂度 242
16.3 软件复杂度案例 242
16.3.1 单元级圈复杂度 243
16.3.2 消息集成级圈复杂度 243
16.4 面向对象复杂度 244
16.4.1 WMC——每个类的加权方法 245
16.4.2 DIT——继承树的深度 245
16.4.3 NOC——子类数量 246
16.4.4 CBO——类之间的耦合性度量 246
16.4.5 RFC——对类的响应 246
16.4.6 LCOM——方法内聚缺乏度 246
16.5 系统级复杂度 246
16.6 习题 246
16.7 参考文献 248
第17章 基于模型的综合系统测试 249
17.1 综合系统的特征 249
17.2 综合系统的实例 250
17.2.1 车库门控制器(受控) 250
17.2.2 空中交通管理系统(告知式) 251
17.2.3 GVSU雪灾应急系统(协作式) 251
17.2.4 磐石联邦信贷联盟(虚拟式) 252
17.3 用于综合系统的软件工程 252
17.3.1 需求引出 252
17.3.2 用UML方言SysML描述方案 253
17.3.3 测试 255
17.4 综合系统的基本通信单元 256
17.4.1 Petri网表示ESML提示符 256
17.4.2 泳道Petri网中的新提示符 258
17.5 综合系统等级对提示符的影响 260
17.5.1 受控式和应答式综合系统 260
17.5.2 协作式和虚拟式综合系统 260
17.6 习题 260
17.7 参考文献 260
第18章 探索式测试 261
18.1 探究探索式测试 261
18.2 探索一个常见示例 263
18.3 观察与结论 264
18.4 习题 265
18.5 参考文献 265
第19章 测试驱动开发 266
19.1 “测试然后编码”的软件开发周期 266
19.2 自动化测试执行(测试框架) 273
19.3 Java和JUnit示例 274
19.3.1 Java源代码 274
19.3.2 JUnit测试代码 276
19.4 其他待解决的问题 277
19.4.1 基于规格说明还是基于代码 277
19.4.2 需要配置管理吗 277
19.4.3 粒度应该多大 277
19.5 测试驱动开发的优缺点及其他相关问题 278
19.6 模型驱动开发与测试驱动开发对比 279
第20章 全对测试详述 282
20.1 全对测试技术 282
20.1.1 程序输入 283
20.1.2 独立变量 284
20.1.3 输入的顺序 286
20.1.4 完全由输入所引发的失效 288
20.2 对NIST研究成果的进一步分析 288
20.3 全对测试的适用范围 289
20.4 对全对测试的建议 290
20.5 习题 290
20.6 参考文献 290
第21章 测试用例的评估 291
21.1 变异测试 291
21.1.1 程序变异的规范化表达 291
21.1.2 突变算子 292
21.2 随机扰动法 296
21.3 鱼篓统计法和故障注入 297
21.4 习题 297
21.5 参考文献 297
第22章 软件技术评审 298
22.1 软件技术评审的经济价值 298
22.2 技术评审中的各种角色 299
22.2.1 产品开发人员 300
22.2.2 评审组组长 300
22.2.3 记录员 300
22.2.4 评审专家 300
22.2.5 角色的多重性 301
22.3 技术评审的分类 301
22.3.1 演练 301
22.3.2 技术检验 301
22.3.3 审计 302
22.3.4 各类评审的比较 302
22.4 一个检查包的内容 302
22.4.1 工作成果需求 302
22.4.2 冻结工作成果 302
22.4.3 标准和清单 303
22.4.4 评审问题电子表格 303
22.4.5 评审报告表格 304
22.4.6 错误的严重等级 304
22.4.7 评审报告大纲 305
22.5 一个工业强度的检查过程 305
22.5.1 提交计划 306
22.5.2 由评审员进行介绍 306
22.5.3 准备 306
22.5.4 评审会议 307
22.5.5 报告的准备 307
22.5.6 部署 307
22.6 有效评审文化 307
22.6.1 规矩 308
22.6.2 管理层参与评审会议 308
22.6.3 两个评审的故事 308
22.7 检查案例分析 309
22.8 参考文献 310
第23章 尾声:软件测试精益求精 311
23.1 软件测试是一种技艺 311
23.2 软件测试的最佳实践 312
23.3 让软件测试更出色的10项最佳实践 313
23.3.1 模型驱动的敏捷开发 313
23.3.2 慎重地定义与划分测试的层次 313
23.3.3 基于模型的系统级测试 313
23.3.4 系统测试的扩展 313
23.3.5 利用关联矩阵指导回归测试 314
23.3.6 利用MM路径实现集成测试 314
23.3.7 把基于规格说明的测试和基于代码的单元级测试有机地结合起来 314
23.3.8 基于单个单元特性的代码覆盖指标 314
23.3.9 维护阶段的探索式测试 314
23.3.10 测试驱动开发 314
23.4 针对不同项目实现最佳实践 314
23.4.1 任务关键型项目 315
23.4.2 时间关键型项目 315
23.4.3 对遗留代码的纠错维护 315
23.5 参考文献 315
附录 完整的技术评审文档集 316