软件测试的艺术 读书笔记完整版
第 1 章 一次自评价测试
定义:
所谓软件测试,就是一个过程或一系列过程,用来确认计算机代码完成了其应该完成的功能,不执行其不该有的操作。
一个三角形类别判定程序的测试用例的评判(评判测试用例的设计水平):
程序功能描述:程序从用户获取 3 个整数输入值,分别代表三角形三条边的长度。程序判断该三角形为不规则三角形、等腰三角形或等边三角形。
对测试用例的评判:
是否有测试用例是一个有效的不规则三角形?
是否有测试用例是一个有效的等腰三角形?
是否有测试用例是一个有效的等边三角形?
是否至少有 3 个测试用例覆盖了等腰三角形的三种情况?如:3、3、4,3、4、3,4、3、3。
是否有测试用例为某边的长度为 0 ?
是否有测试用例为某边的长度为负数?
是否有测试用例其中两边之和等于第三边的长度?
是否至少有 3 测试用例覆盖了两边之和等于第三边的全部 3 种情况?
是否有测试用例其中两边之和小于第三边的长度?
是否至少有 3 测试用例覆盖了两边之和小于第三边的全部 3 种情况?
是否有测试用例为 3 条边的长度均为 0 ?
是否有测试用例输入的边长符合不规则三角形要求但为非整数?
是否有测试用例输入的边长个数不对?
对于每一个测试用例,除了定义输入情况以外是否同时定义了相对的预期输出值?
10.特殊字符
第 2 章 软件测试的心理学和经济学
软件测试的心理学
应当一开始就假设程序中隐藏着错误,然后执行测试去尽可能多地发现程序的错误。实际上,这种假设是几乎对所有程序都成立的。所以,测试的另一种定义为:测试是为发现错误而执行程序的过程。拥有这样的观念,其实是把测试的定位拔高了一筹:测试会找出并推荐修改程序的错误,从而提高程序的可靠性和质量。
心理学影响测试的另一个效应是,人类行为总是倾向于具有高度目标性,如果我们的目的是要证明程序中不存在错误,我们潜意识中就会倾向于选择可能较少导致程序失效的测试方法和数据。反之,我们的目标定位尽可能多地发现程序的错误,就会设计并更好地执行较优的测试方法。
还有一个心理学效应或说概念,是关于“成功与否的测试”。如果认为发现了程序错误的测试称为不成功,而没有发现程序错误的称为成功,那就是本末倒置了。但基本大多数人一不留神就会倾向于这么想。需要警惕。
另一个需要警惕的是,如果软件测试的目标是证明软件做了应该做的,也就是该有的功能都有了,就不易发现软件还有一类错误:做了不该做的。
软件测试的经济学
黑盒测试:
对于具有一定复杂性的程序,较真起来,测试将几乎永远也做不完。因为要发现程序中的所有错误常常是不可能的。那么到底需要做到什么程度呢?这就需要引入“经济学”的思考方法,综合多种考虑因素,合理选择合适的测试策略。
测试的目标:
通过有限的测试用例极大限度的提高发现问题的数量,取得最好的测试效果。
白盒测试:
软件测试的原则
- 每个测试用例必须明确定义输入数据与预期输出。
- 避免由开发人员测试自己编写的程序。
- 避免由开发团队测试自己开发的程序。
- 彻底检查每个测试用例的执行结果。
- 测试用例应当覆盖无效的输入和未预料到的输入情况。
- 需要同时检查程序“做了应该做的”和“没做不应该做的”。
- 避免设计的测试用例用完即弃。
- 规划测试工作时不能假定测试不会发现错误。
- 程序多个模块相较而言,某个模块存在的未发现的错误数量,与已发现的错误数量成正比。
- 软件测试是一项极富创造性、极具智力挑战性的工作。
回归测试:
保持测试用例,当程序其他部件发生变动后重新执行。
第 3 章 代码检查、走查和评审
代码检查与走查
- 代码检查、代码走查以及可用性测试是三种主要的人工测试方法。可用性测试将在后续章节讲解。这种人工测试方法与基于计算机的测试是互补的。
- 代码检查和代码走查都是主要以评审会议的形式开展,不同之处是前者有开发人员逐行讲解代码,与会人员根据代码检查的错误列表检查代码,后者稍微复杂点,需要专门的测试人员提前设计简单的测试用例,与会者在脑里过这些测试用例,并向开发人员提问,从而发现程序缺陷。
- 评审会议的注意事项:
- 讨论促进问题的发现,勿讨论错误的修正方法。
- 讨论只针对发现的问题,勿真的开发人员本身。
- 开发人员必须怀着非自我本位的态度来对待检查过程,采取积极和建设性的态度。
- 组织人员提前发放相关资料,各参与人员都需要提前做好准备工作。
用于代码检查的错误列表
-
数据引用错误
-
数据声明错误
-
运算错误
-
比较错误
-
控制流程错误
-
接口错误
-
输入输出错误
-
其他检查
1、数据引用错误
1)是否有引用的变量未赋值或未初始化?
2)下标的值是否在范围之内?
3)记录和结构的属性是否匹配?
4)是否计算位串的地址?是否传递位串参数?2、运算错误
1)是否存在非算术变量间的运算?
2)是否存在混合摸式的运算?
3)是否存在不同字长变量问的运算?
4)目标变量的大小是否小于赋值大小?
5)中间结果是否上溢或下溢?
6)是否存在二进制的不精确度?3、数据声明错误
1)数组和字符串的初始化是否正确?
2)变量是否赋予了正确的长度,类型和存储类?
3)是否所有的变量都已声明?4、控制流程错误
1)是否每个循环都终止了?
2)是否存在由于入口条件不满足而跳过循环体?
3)可能的循环越界是否正确?
4)是否存在“仅差一个”的迭代错误?5、输入输出错误
1)文件的属性是否正确?文件在使用前是否打开使用后是否关闭?文件结束条件是否被正确处理?
2) I/O语句是否符合格式规范?是否处理了I/O 错误?
3)缓冲大小与记录大小是否配?6、内存错误
1)为指针分配内存后,是否判断指针是否为null?
2)指针使用前是否赋初值?
3)数组或指针的下标是否越界?
4)内存申请和释放是否匹配?
5)将指针所指向的内存释放后,是否第一时间将指针置为null?(防止使用“野指针”)
6)是否将函数内部的局部变量(分配在栈上)作为返回值?
桌面检查
桌面检查是一种比较古老的人工检查方法,就是简单的由一个人阅读程序,对照错误列表检查程序。当然基于前面提到的软件测试原则,最好还是由非本程序的人员来检查比较好。
同行评审
同行评审是一种依据程序整体质量、可维护性、可扩展性、易用性和清晰性对匿名程序进行评价的技术。其目的是为程序员提供评价的手段。
第 4 章 测试用例设计
测试用例设计的基调
首先,“完全的测试是不可能的”,意思是我们不可能设计出全部的测试用例来对软件进行测试。正确的方法是,在所有可能的测试用例中,找出有可能发现最多错误的那个用例子集。
这就需要用的一定的测试策略,包括黑盒测试和白盒测试两大类。对于白盒测试,主要就是从覆盖程序的逻辑结构出发设计测试用例。而黑盒测试包括等价类划分、边界值分析、因果图分析、错误猜测几类。
组合的测试策略:
如果规格说明中包含输入条件的组合情况,应首先使用因果图分析方法。
在任何情况下都使用边界值分析方法。
注意同时考虑有效等价类和无效等价类。
用错误猜测技术增加更多的测试用例。
使用白盒测试的覆盖分析方法针对上述测试用例集的覆盖情况进行检查。
白盒测试
可靠性由高到低:多重条件覆盖准则>判定/条件覆盖准则>分支覆盖>判定覆盖>语句覆盖
白盒测试的逻辑覆盖的几个层次:
-
语句覆盖
-
判定覆盖:要求每个判断都必须有“是”和“否”的结果,而且每个入口点都必须至少被调用一次。
-
条件覆盖:确保将一个判断中的每个条件的所有可能的结果至少执行一次。
-
判定/条件覆盖:设计出充足的测试用例。将一个判断中的每个条件的所有可能的结果至少执行一次;将每个判断的每个条件的所有可能的结果至少执行一次;将每个判断的所有可能的结果至少执行一次;将每个入口点都至少调用一次。
缺点:看上去所有条件的所有结果似乎都执行到了,但由于有些特定的条件会屏蔽其他条件,所以不能全部执行到。
-
多重条件覆盖:要求编写足够多的测试用例,将每个判定中的所有可能的条件结果的组合,以及所有的入口点都至少执行一次。
最后的多重条件覆盖是覆盖情况最好的,对于前面几个的覆盖情况也是包含的关系。其用例设计方法为:
-
将每个判断的所有结果都至少执行一次。
-
将每个判断的所有可能的条件结果的组合都至少执行一次。
-
将所有的程序入口都至少调用一次。
黑盒测试
等价划分
等价类:如果等价类的某个测试用例发现了某个错误,该等价类的其他测试用例也应该能发现这个错误。相反,如果该测试用例没能发现错误,那么其他测试用例也不能发现错误。当然了,这是一个理想状态下的划分。
有效等价类与无效等价类:有效等价类代表对程序的有效输入,而无效等价类代表的是其他任何可能的输入条件。
根据给定的输入规则和外部条件确定等价类:
- 如果输入条件规定了一个取值范围,确定一个处于范围的有效等价类,两个在范围两端之外的无效等价类。
- 如果输入条件规定了取值的个数,确定一个符合个数规定的有效等价类,一个没有输入的、一个超出个数的无效等价类。
- 如果输入条件规定了一个输入值的集合,确定集合里每一个元素一个有效等价类,一个集合之外的值的无效等价类。
- 如果存在输入条件规定了“必须是”的情况,确定一个满足的有效等价类,一个不满足的无效等价类。
然后就可以根据确定好等价类进行用例设计了。原则是:
- 设计测试用例,尽量覆盖多个还没被用例覆盖的有效等价类,直到全部覆盖。
- 设计测试用例,一次只覆盖一个无效等价类,直到全部覆盖。
边界值分析
所谓边界条件,是指输入和输出的可能情况中那些恰好处于边界、超过边界、在边界以下的情况。这与等价类是有点相似,不同点在于:
-
等价类没那么关注刚好处于边界值的情况。
-
等价类没那么关注输出的边界情况。
分析指南:
-
如果输入条件规定了一个取值范围,应当设计两个边界值、两个边界值之外取值的共 4 个用例。
-
如果输入条件规定了输入值的数量,应当设计一个 0 个、一个最小数量、一个最大数量、一个超出范围共 4 个用例。
-
对每个输出条件应用指南 1 。
-
对每个输出条件应用指南 2 。
-
如果输出或输出是一个有序序列,需要特别注意覆盖序列的第一个和最后一个元素。
因果图分析
前面的等价类划分和边界值分析只关注与软件的输入和输出规格,对于更多的规格说明,可以对应整理出因果图进行进一步的逻辑分析,从一个不同的视角,或者说更系统性的视角来设计测试用例。其分析设计过程如下:
- 将规格说明分解为可执行的片段。
- 确定规格说明中的因果关系。
- 分析规格说明的语义内容,将其转换为连接因果关系的布尔图。
- 给图加上输出输出的约束关系说明等注解符号。
- 跟踪因果图的状态变化,转换为一个判定表。
- 将判定表中的列转换为测试用例。
错误猜测
错误猜测不算是什么测试用例设计的策略。其实就是设计人员的潜意识和直觉。不过也是有其特点:
- 根据经验列出可能犯的错误和容易犯错误的地方,然后针对设计用例。
- 针对规格说明书中未明确说明,程序员认为显而易见的或包含程序员“假设”的地方进行用例设计。
第 5 章 模块(单元)测试
分三大块介绍单元测试:
- 测试用例的设计方式
- 模块测试及集成的顺序
- 对执行模块测试的建议
模块测试的目的:
是将模块的功能与定义模块的功能规格说明或接口规格说明进行比较。这里测试的目标不是为了说明模块符合其规格说明,而是为了揭示出模块与其规格说明存在矛盾。
模块测试的步骤:
1)测试用例的设计
2)执行模块测试和集成的顺序
模块测试的测试用例设计如下:
使用一种或多种白盒测试方法分析模块的逻辑结构,然后使用黑盒测试方法对照模块的规格说明以补充测试用例
非增量测试:先独立地测试每个模块,然后再将这些模块组装成完整的程序。又叫“崩溃(big-bang)”测试。
增量测试:先将下一步要测试的模块组装到测试完成的模块集合中,然后再进行测试。又叫集成测试。1)自顶向下;2)自底向上
测试用例设计:
-
模块测试适用于规模较大的程序。
-
模块测试是对程序中的单个子程序、模块或过程进行测试的过程,并不是一上来就对整个程序进行测试,而是先把注意力集中在构成程序的小模块的测试上面。
-
模块测试中的测试用例设计设计过程:使用一种或多种白盒测试方法分析模块的逻辑结构,然后使用黑盒测试方法对照模块的规格说明书以补充测试用例。
增量测试
- 非增量测试或说崩溃(big-bang)测试:先独立地测试每个模块,最后再把所有这些模块组装成完成的程序。
- 增量测试或说集成:每一步把未测试的模块集成到已测试的模块当中进行测试,如此往复,直到所有模块集成为完整的程序。
- 增量测试的优点(非增量测试的缺点)
1. 增量测试的总的工作量要少一些。因为非增量测试中的每一个模块的测试,都需要写对应的驱动模块和桩模块以辅助测试。
2. 增量测试可以尽早发现模块之间的不匹配的接口与假设。
3. 增量测试会将测试进行得更彻底。因为不断集成,覆盖了更多的情况。
增量测试的缺点(非增量测试的优点):
- 非增量测试占用的机器时间较少。毕竟每次测试都是针对单个模块,而不是集成越来越多的模块。
- 非增量测试的执行可以有更高的并行性。
- 增量测试分为自底向上与自顶向下两种,各有优缺点。
第 6 章 更高级别的测试
概述
不同级别的测试
- 模块测试的目的是发现程序模块与其接口规格说明之间的不一致。
- 功能测试的目的是为了证明程序未能符合其外部规格说明。
- 系统测试的目的是为了证明软件产品与其初始目标不一致。
开发过程与测试过程的对应关系
系统测试
注意认识误区:系统测试并非是测试整个系统或程序功能的过程,而是要跳出来,将系统或程序与其初始目标进行比较。
分类
-
能力测试:确保程序的目标功能实现
-
容量测试:发现处理大容量数据时的程序异常
-
强度测试:发现在大规模负载、高强度不间断持续的数据处理中的异常
-
可用性测试:评估最终用户在使用软件并与软件交互时存在的可用性问题
可用性测试主要是关注“人的因素”。而这其中应当检查的项包括:
- 是否每一个用户交互设计都考虑到最终用户的理解力、教育背景以及环境压力?
- 程序的输出是否有意义、没有侮辱性词语,以及是否含糊不清?
- 用来错误诊断的提示信息是否直白易懂?
- 用户界面上是否保持概念的一致、内部的连贯性、语法的一致性?
- 软件是否提供了足够有效的输入验证?
- 系统是否包含了太多选项,后者包含的一些选项不会被使用?
- 对于来自用户的输入,系统是否能够及时作出反应?
- 程序的操作是否很容易上手?
- 软件的设计是否有助于用户准确输入?
- 用户的操作可以轻松重复吗?用户是否确定能够在众多的功能和菜单中来回切换而不发生意外?
- 软件的功能实现是否达到了设计规格要求?
-
安全性测试:试图攻破程序的安全防线
-
性能测试:评估程序的的响应时间和吞吐率
-
存储测试:确保程序可以正确处理其对存储的需求
-
配置测试:检查程序是否能在推荐配置上流程运行
-
兼容性/转换测试:评估新版本是否能兼容老的版本
-
安装测试:确保能够在所有支持的平台上安装软件
-
可靠性测试:评估程序是否能达到规格说明中的运行时常和平均故障间隔时间要求
-
可恢复性测试:测试系统恢复相关的功能是否按设计要求实现
-
服务/可维护性测试:评估系统是否拥有良好的数据处理和日志机制,以备技术支持和调试之需
-
文档测试:校验所有用户文档是否准确
-
过程测试:对软件操作系统或维护所需涉及的流程进行评估和确定
验收测试
验收测试是将程序与其最初的需求及最终用户当前的需要进行比较的过程。该测试通常是有程序的客户或最终用户来进行。
Alpha测试是由用户在开发环境下进行的测试,也可以是开发机构内部的用户在模拟实际操作环境下进行的测试。开发者坐在用户旁边,这是在开发者受控的环境下进行的测试。由开发者随时记录下错误情况和使用中的问题。
Beta测试是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。开发者通常不在测试现场,这是在开发者无法控制的环境下进行的测试。由用户记录下遇到的所有问题,定期向开发者报告。beta测试是一模拟真实的使用环境从而发现缺陷的一种测试
6.4 安装测试
安装测试:1)用户必须选择大量的选项。2)必须分配并加载文件和库。3)必须进行有效的硬件配置。4)软件可能要求网络联通,以便与其他软件连接
测试的计划与控制
测试计划应当考虑的方面:
-
目标,每个阶段都需要清晰地目标
-
结束准则,制定标准以判断每个阶段做到何种程度可以结束
-
速度,也就是各个阶段的执行时间表
-
责任
-
测试用例库及标准
-
工具
-
计算机时间
-
硬件配置
-
集成
-
跟踪步骤
-
调试步骤
-
回归测试
测试结束准则
第一类准则
- 适用于模块测试的结束准则:来源于多重条件覆盖、边界值分析的所有测试用例都已不能发现新的软件缺陷。
- 适用于功能测试的结束准则:来源于因果图分析、边界值分析、错误猜测的所有测试用例都已不能发现新的软件缺陷。
第二类准则
准则规定发现了某个既定数量的缺陷后,可以结束测试。这依赖于提前对软件开发的各个阶段的各种类别的缺陷总数量有较为准确的预估。
预估方法有:
- 参考以往开发的程序的实际情况;
- 预先插入不公开的种子错误,测试一段时间后按比例计算种子错误和总错误数;
- 参考行业范围内的平均值等。
第三类准则
详细记录测试过程的缺陷发现数据,绘制曲线图,查看变化趋势,可以在缺陷发现数量已从最高峰下降到较低水平时结束测试。
第 7 章 调试法
调试是一个包含两个步骤的过程,从执行了一个成功的测试用例、发现了一个问题之后开始。
第一步,确定程序中可疑错误的准确性质和位置;
第二步,修正错误。
蛮力法调试
-
利用内存信息输出来调试。
-
根据一般的“在程序中插入打印语句”建议来调试。
-
使用自动化的调试工具进行调试。
缺点:
都忽略了思考的过程
归纳法调试
-
确定相关数据。
-
组织数据。
-
作出假设。
-
证明假设。
-
解决问题。
演绎法调试
-
列举出所有可能的原因或假设。
-
利用数据排除可能的原因。
-
提炼剩下的假设。
-
证明剩下的假设。
-
修复问题。
回溯法调试
-
根据实际代码流程进行分析。
-
如果说归纳法是数据分析,演绎法是逻辑分析,回溯法就是代码分析。
测试法调试
编写专用的测试用例进行辅助调试。
调试的原则
- 定位错误的原则:
- 静下来动脑筋,思考程序本身的设计与出现的错误。
- 如果遇到了僵局,就留到稍后解决。让潜意识工作一会儿。
- 尝试把遇到的问题描述给他人听,激发自己的思考。
- 仅将调试工具作为第二种手段。
- 避免使用试验法,仅将其作为最后手段。
- 修改错误的技术:
-
存在一个缺陷的地方,很有可能还存在其他缺陷。
-
应纠正错误本身,而不仅是其症状。
-
正确纠正错误的可能性并非 100% 。
-
随着程序规模的增加,正确修改错误的可能性反而降低。
-
改正错误有引入新错误的可能性。
-
修改错误的过程也是临时回到设计阶段的过程。
-
应修改源代码,而不是目标代码。
错误分析
程序员可以通过详细分析出现的错误,从而提高自己的水平。分析的思路有:
- 错误出现在什么地方?
- 谁制造了这个错误?
- 哪些做的不正确?
- 如何避免该错误的出现?
- 为什么错误没有早些发现?
- 该如何更早地发现错误?
第 8 章 敏捷软件开发宣言
- 我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观
- 个体和互动高于流程和工具。
- 工作的软件高于详尽的文档。
- 客户合作高于合同谈判。
- 响应变化高于遵循计划。
- 也就是说,尽管右项有其价值,我们更重视左项的价值。
敏捷开发的特征
- 依赖客户的参与。
- 测试驱动。
- 紧凑的迭代开发周期。
敏捷测试
本质上,敏捷测试是协同测试的一种形式,它要求每一个人都参与到测试计划的设计、实现以及执行中去。他们的任务是通过持续的测试反馈推动项目进行,帮助开发者修复缺陷。
极限编程与测试
- 极限编程(XP)的关注点是:
- 实现简单的设计。
- 开发人员与客户的沟通协作。
- 不断地测试代码库。
- 重构以适应规格说明的变更。
- 寻求用户的反馈。
-
XP 更倾向于适合中小规模的软件开发,这些软件的规格说明变更非常频繁,而且它们还可以进行接近实时的沟通。
-
单元测试是极限测试中采用的主要测试方法,它具有两条简单规则:所有代码模块在编码开始之前必须设计好单元测试用例,在产品发布之前必须通过单元测试。
第 9 章 互联网应用测试
互联网应用的最大特点
消费者无需为访问的网站付费,因此一旦面对的是一般化的网站设计或性能,人们可能会很快离开该网站而去选择竞争对手的网站。
电子商务的基本结构
- 三层 C/S 结构
- 表示层:使用 HTML 或 CGI 等生成的动态或静态的页面。
- 业务层:处理业务逻辑。
- 数据层:数据库管理系统。
测试的挑战
- 用户群庞大且五花八门。
- 业务环境。与实际业务结合。
- 地点。国际化问题。
- 安全性。防止攻击,保证可用性。
- 测试环境。搭建各种各样可能的运行环境与用户环境。
测试的策略
- 表示层的测试
- 内容测试。包括审美、字体、色彩、拼写、内容准确性和默认值。
- Web 站点结构。包括无效的链接和图形。
- 用户环境。浏览器版本、操作系统版本等。
- 业务层的测试
- 性能。响应时间、同时在线用户数等。
- 数据有效性。检测从用户获取的数据的有效性。
- 事务。业务逻辑。
- 数据层的测试
- 响应时间。数据存入、查询、读取的耗时。
- 数据完整性。正确存储。
- 容错性和可恢复性。最大化 MTBF,最小化 MTTR。
第 10 章 移动应用测试
移动环境
- 我们所说的移动设备,特指能够运行那些需要访问移动网络的应用程序的电子产品。
- 移动应用测试环境需要考虑的因素
- 需要理解设备连接问题和网络速度、有效区域以及网络延时。
- 考虑设备的多样性、设备的各种限制、设备的输入手段。
- 需要确定以何种方式安装和维护应用程序。
测试面临的挑战
- 设备多样性
- 操作系统、浏览器、应用程序运行时环境、屏幕分辨率、人机交互界面和接口、人体工程学设计、屏幕尺寸等。
- 运营商网络基础设施
- 自动化脚本编程与开发
- 可用性测试
测试方法
- 真机测试
- 基于模拟器的测试
参考:
软件测试的艺术—Glonford J.Myors
https://blog.****.net/u013547284/article/details/70856026
https://blog.****.net/engrossment/article/details/92002243