软件测试:提高软件质量的重要手段。
确认是否达到可用级别(用户需求)。
测试跟其他活动的目标相反——破坏、证错、负能量。
再好的测试也无法证明系统无错。
什么是好的测试?
能发现错误,不冗余,最佳特性,别太复杂也别太简单。
测试等级分为单元测试->集成测试->系统测试->验收测试、回归测试。
回归测试:代码发生变更或修复 bug
后,重新运行之前的测试(单元、集成或系统级别),以确保新代码没有破坏原有已正常工作的核心功能。
白盒测试:对程序内部代码结构的测试。
黑盒测试:对程序外部表现出来的行为的测试。
1.暴力穷举不可行——用例空间太大。
2.随意测试效率低下——靠偶然性测试没有意义。
3.统计学采样不适用于软件。
目标从“使其运行”变成“使其出错”。
学会对自己的代码暴力些。
测试用例=输入+执行条件+期望结果
1.最可能发现错误。
2.不重复不冗余
3.最有效
4.既不简单也不复杂
在写代码前写测试。
先写spec,再写符合spec的测试样例,再写代码实现。
spec:软件需求规范,描述软件系统功能和性能要求的文档。
写测试用例,就是理解,修正,完善spec设计的过程。
针对程序中最小单元模型开展测试,隔离各个模块,容易定位错误和调试。
只检查功能,不关心源代码。
检查程序是否符合规约。
检测错误种类:
1.功能错误或遗漏
2.接口错误
3.数据结构或外部数据库访问错误
4.行为或性能错误
5.初始化或终止错误
用尽可能少的测试用例,在尽可能短的时间内,最大限度地验证程序的合规性。
将被测函数的输入域划分为等价类,从等价类中导出测试用例。
针对每个输入数据需要满足的约束条件,划分等价类。
等价关系:自反、对称、传递。
每个等价类代表着对输入约束加以满足/违反的有效/无效数据集合。
核心假设:相似的输入=相似的行为。
选择不相似的用例——降低测试用例数量的同时保证测试覆盖率。
等价类划分指南:
1.限定数值范围——定义1个有效等价类和2个无效等价类。
2.指明特定的值——定义1个有效等价类和1个无效等价类。
3.确定一组数值——定义1个有效等价类和1个无效等价类。
4.输入为布尔值——定义1个有效等价类和1个无效等价类。
例子与练习。
大量的错误发生在输入域的边界而不是中央。
边界值分析已经成为一个测试技术。
程序员经常犯大小差1的错误。
某些边界值是特值,需要特殊处理。
程序的行为在边界可能突变。
等价类划分时,将边界作为等价类之一加入考虑。
边界值划分指南:
1.5个测试用例——最小,略高于最小,正常,略低于最大,最大。
2.增加1个略高于最大和1个略低于最小。
笛卡尔积:全覆盖。
多个划分维度上的多个取值,要组合起来,每个组合都要有一个用例,但并非所有组合情况都可能。
测试完备,但用例数量多,测试代价高。
覆盖每次取值:最少1次即可。
每个维度的每个取值至少被1个测试用例覆盖一次即可。
测试用例数量少,代价低,但测试覆盖度未必高。
黑盒测试完全从函数spec导出测试样例,不考虑函数内部。
白盒测试要考虑内部实现细节。
根据程序执行路径设计测试用例。
白盒测试用例:
1.保证路径覆盖。
2.覆盖逻辑决策。
3.边界循环执行。
4.验证内部数据结构。
独立/基本路径测试——对程序所有执行路径进行一次等价类划分,找出最有代表性最简单的路径,设计测试用例使每一条基本路径被至少覆盖一次。
已有的测试用例多大程度覆盖了被测程序。
代码覆盖度低,测试不充分。代码覆盖度高,测试用例多,测试代价高。
覆盖率指标:函数覆盖,语句覆盖,分支覆盖,条件覆盖,路径覆盖。
测试效果:路径覆盖>分支覆盖>语句覆盖。
测试难度:路径覆盖>分支覆盖>语句覆盖。
白盒测试最彻底的办法是路径覆盖,但路径数量巨大,难以覆盖全。
实际当中,根据预先设计的覆盖度标准,逐步增加测试用例数量,直到覆盖度达标。
手工测试代价太高,最好达到完全自动化。
自动调用被测函数、自动判定测试结果、自动计算覆盖度。
一旦程序被修改,重新执行之前的所有测试。
一旦发现bug,要马上写一个可以重现该bug的测试用例,并且将其加入测试库。
自动化回归测试。
测试策略(根据什么选择测试用例)非常重要,需要在程序中显式记录下来。
目的:在代码评审过程,其他人能理解你的测试,并评判你的测试是否足够充分。
测试优先编程:在编写实际代码前编写测试用例。
划分与边界:用于系统化选择测试用例的方法。
白盒测试与语句覆盖:用于完善和补充测试套件。
单元测试:尽可能孤立对每个模块进行独立测试。
自动化回归测试:防止已修复的bug再次出现。
远离bug:测试的本质是为了发现代码中的bug,而测试优先编程的意义在于尽可能早地发现它们——即在Bug被引入代码后瞬间将其揪出来。