资料来源:软件构造PPT
软件测试与测试优先
PART Ⅰ 测试相关知识点
Q:为什么要测试?
测试能够发现程序中的错误,提高程序正确性的信心。
Q:测试需要注意哪些点?
- 正确性
- 需求是否满足spec
- 对所有输入能否正确相应(robustness)
- 性能能否接受,运行时间能够接受
- 是否可用
- 能否正确的安装部署和运行
- 能否实现期望
Q:一个好的测试具有哪些特征?
- 能够发现错误
- 不冗余
- 能够最佳测试要测试的函数
- 不是太复杂也不是太简单
Q:测试的等级有哪些?
最底层:单元测试,测试功能函数
中间层:集成测试,对于多个类、包、组件的集中测试
顶层:系统测试,测试一个完整的系统
-
回退:回归测试,重复迭代
image -
最终交付:验收测试
image
Q:静态测试与动态测试区别?
-
静态测试不会实际的运行代码
静态测试常常是内部运行的,比如在代码工具/文本编辑器中会检查代码的结构或者编译器检查语法和数据流。
-
动态测试测试代码运行的表现,也就是会在测试用例中真正的跑起来
在代码未完全实现之前,动态检查会检查特定的代码段,现在用来动态测试的技术要么是驱动或者在debug环境中执行。
Q:测试和调试的区别(testing vs. debugging)?
- 测试是用来发现是否存在错误
- 调试是用来识别错误根源,消除错误
PART Ⅱ 软件测试用例选择
接下来就要说一下软件测试了。
Q:为什么说软件测试很难?
- 行为在离散输入空间中差异巨大,输入并不符合统计学规律。bug的出现不符合概率分布。
- 在错误发生时,输入无统计分布规律可循
- 暴力穷举是不可能的
所以说,软件测试用例必须要慎重和系统的选择
Q:测试用例是什么东西?
测试用例是一个测试输入、执行条件、预期结果的集合。测试用例是你项目中有价值的资产!
Q:测试用例的设计原则?
- 有代表性
- 明确性,有明确的结果
- 可重复性,同一case,同一结果
PART Ⅲ 测试优先编程
Q:什么叫测试优先编程?
在你写代码之前,先把测试写好
Q:具体的流程应该是什么?
- 先写spec
- 再写符合spec的测试用例
- 写代码 --> 执行测试 --> 修改 ,重复
Q:SPEC怎么写?
- 给输入的参数类型和约束条件,比如平方函数不能是负的。
- 给出返回值和以及返回值和输入之间关系
- spec也包括方法的特点和有关它是用来干啥的评述
当然,SPEC是不可能一次就写好的,所以我们得写测试用例,写测试用例,可以理解、修正、完善spec设计。
Q:先写测试还是后写呢?
题目叫什么??当然是先写
Q:什么叫测试驱动开发?
测试驱动开发(TDD),就是以测试驱动开发。先写需求,再写测试,然后编程实现通过测试,循环。短平快,跟之前先编码,后来发现对不上需求的编码方式相反。
PART Ⅳ 单元测试 Unit Test
Q:什么叫单元测试?
针对软件最小单元模型开展测试,隔离各个模块,容易定位错误和调试
Q:那么单元测试要考虑哪些情况呢?
- 模块的接口,确保数据流正确的输入和输出。
- 本地的数据结构,确保在经过算法计算后结构不会变。
- 各个独立分支,确保所有控制结构,条件分支都能测试到。
- 边界条件,不多说了。
- 针对错误的解决方法。
Q:有没有自动测试工具?
有,JUnit
,测试文件要单独放在test
文件夹下.使用assert语句来判断。
PART Ⅴ 黑盒测试(重要)
Q:什么是黑盒测试?
黑盒测试不关心代码如何实现,只检查代码的功能。
ⅰ以划分来选择测试用例
Q:什么叫等价类划分?
将函数的输入域划分为等价类,从等价类中导出测试用例。其中根据每个输入所需要满足的约束条件,划分等价类。每一个等价类都代表着对约束加以满足/违反/无效的数据集合。
Q:等价类划分的一般规则?
- 输入数据限定了范围,那么就会产生一个合法域和两端的非法域。
- 输入数据指明了特定的值,那么就会产生一个合法值和一个非法值。
- 输入数据确定了一组数据,那么就有一组合法和一组非法数据。
- 输入数据为yes | no,我不说了。
例:输入学号
- 长度为10位,:10、>10、<10
- 117开头:以此开头、以其他开头
- 后两位数为特定数字
Q:对于数字测试如何划分?
- 根据约束
- 考虑很大的数
例:
multiply()
函数
每个划分内选一个就足够代表了
例:
max()
函数
练习:
ⅱ 在划分中包含边界
-
大量的错误发生在输入域的边界而非中央
- 0是正负的边界
- 最大数MAX和最小数MIN对于int和double是边界
- 空对象(empty string、empty list、 empty array)对于collection是边界
- collection的第一个和最后一个是边界
BVA(boundary value analysis)是测试技巧,在边界中选择测试用例
边界值分析方法是对等价类划分方法的补充
在考虑边界划分时,不仅要考虑边界,还要考虑边界的两侧
边界测试的例子:
边界测试加上划分例子:
边界测试例子max函数
ⅲ 两种极端的划分
-
笛卡儿积:全覆盖
在多个维度划分的多个取值,全部组合起来,每个组合都要有一个用例。
-
覆盖每个取值,最少1次即可
在每个维度选择至少一个用例,但不需要测试所有的组合。
两者的区别:
前者测试完备,但数量多,测试代价高。后者测试用例少,代价低,但覆盖度未必高。
PART Ⅵ 白盒测试
白盒测试要考虑内部实现的细节,使用内部视角来编写测试用例。根据程序执行的路径设计测试用例,一般较早执行。也就是说,白盒测试需要覆盖被测代码的所有路径
ⅰ 代码覆盖度
代码覆盖度有很多不同的种类
- 函数覆盖:测试的函数是否被调用
- 语句覆盖:每条语句是否被执行
- 分支覆盖:if while for的每个分支,正确或错误分支是否都被执行
- 条件覆盖:同上
- 路径覆盖:程序的每条执行路径path(各种执行路线)是否 被用例覆盖
测试效果:
路径覆盖 > 分支覆盖 > 语句覆盖
当然……测试难度也是这样从高到低
推荐工具:EclEmma
PART Ⅶ 自动测试与回归测试
事实上,手工测试的代价太高,最好达到完全的自动化
自动测试
意思为自动调用被测函数、自动判定测试结果、自动计算覆盖度。这里只是指测试用例的自动执行,而不是自动生成测试用例。
回归测试
一旦程序被修改,重新执行之前的所有测试。在这里
- 一旦发现bug,马上写一个可以重现bug的输入的测试用例,并将其加入测试库
- 自动测试和回归测试几乎都用在合并代码构建中
- 自动化回归测试是现代软件工程中的最佳实践方式
PART Ⅷ 编写测试策略
在ADT设计文档中,单元测试策略是非常重要的一环。写它的目的是在代码评审中,让其他人可以理解你的测试,检查你的测试是否足够充分。
比如,在测试函数时,在测试类顶部写下测试策略,在每个测试函数上写下它的测试用例是怎么选择的,也就是这个测试覆盖了哪些划分类。
本章小结
- 测试优先编程。
- 划分和边界,能够系统的选择测试用例
- 白盒测试和statement覆盖来填充测试
- 单元测试,使得每个测试尽可能独立不耦合
- 自动回归测试
- 免于遭受bug