1 一次自评价的测试
2 软件测试的心理学和经济学
黑盒测试: 穷举输入测试
白盒测试: 穷举路径测试:将程序中的每条语句至少执行一次
问题 :
1. 逻辑错误,不符合设计规范
2. 缺少路径
3. 数据敏感
软件测试的重要原则:
- 测试用例中一个必要部分是对预期输出或结果进行定义
- 程序员应当避免测试自己编写的程序
- 编写软件的组织不应该测试自己编写的软件
- 应当彻底检测每个测试用例的结果
- 测试用例的编写不应当根据有效的预料到的输入情况,而且也应当根据无效的和未预料到的输入情况
- “未做其应当做的” + “做了其不应该做的”
- 避免测试用例用后即弃。 ——回归测试
- 计划测试工作时不应默许假定不会发生错误
- 程序某部分存在更多错误的可能性,与该部分已发现的错误成正比
- 软件测试是一项极富创造性,极具智力挑战性的工作。
3 人工测试——代码检测、走查与评审
数据引用错误
- 是否有引用的变量未赋值或未初始化
- 下标的值是否在范围之内
- 是否存在非整数下标
- 是否存在虚调用 (所有通过指针或引用变量的引用,当前引用的内存单元是否分配)
- 当使用别名时,属性是否正确*(当一个内存区域内具有不同属性的别名,当通过别名引用时,内存区域中的数据值是否具有正确的属性)*
- 记录*(数据)*和结构的属性是否匹配
- 是否计算位串的地址?是否传递位串参数?* 当内存分配的单元小于内存可寻址的单元大小时,是否存在直接或间接的寻址错误*
- 当使用指针或引用变量时,被引用的内存的属性是否与编译器所预期的一致。
- 跨过程的结构定义是否一致。
- 索引或下标是否有“差一个”的错误
- 继承需求是否得到满足
运算错误
- 是否存在非算术变量间的运算
- 是否存在混合模式的运算
- 是否存在不同字长变量间的运算
- 目标变量的大小是否小于赋值大小
- 中间结果是否上溢或下溢
- 是否存在被0除
- 是否存在二进制的不精确度
- 变量的值是否超过了有意义的范围
- 操作符的优先顺序是否被正确理解
- 整数除法是否正确
数据声明错误
- 是否所有的变量都已声明
- 默认的属性是否被正确理解
- 数组和字符串的初始化是否正确
- 变量是否赋予了正确的长度、类型和存储类
- 初始化是否与存储类型一致
- 是否有相似的变量名
比较错误
- 是否存在非算术变量间的比较
- 是否存在不正确的混合模式的比较运算
- 比较运算符是否正确
- 布尔表达式是否正确
- 比较运算符与布尔表达式的混合,导致计算机理解错误
- 是否存在二进制小数的比较
- 操作符的优先顺序是否被正确理解
- 编译器对布尔表达式的计算方式是否被正确理解
控制流程错误
- 是否超出了多条分支路径
- 是否每个循环都终止了
- 是否每个程序都终止了
- 是否存在由于入口条件不满足而跳过的循环体
- 可能的循环越界是否正确
- 是否存在“差一个”的迭代错误
- do/end 是否匹配
- 是否存在不能穷尽的判断
- 输出信息中是否有文字或语法错误
输入/输出错误
- 文件属性是否正确
- open语句是否正确
- I/O语句是否符合格式规范
- 缓冲大小与记录大小是否匹配
- 文件在使用前是否打开
- 文件在使用后是否关闭
- 文件结束条件是否被正确处理
- 是否处理了I/O错误
接口错误
- 形参数量是否等于实参数量
- 形参的属性是否与实参的属性相匹配
- 形参的量纲是否与实参的量纲相匹配
- 传递给被调用模块的实参个数是否等于其形参个数
- 传递给被调用模块的实参属性是否与其形参属性匹配
- 传递给被调用模块的实参量纲是否与其形参量纲匹配
- 调用内部函数的实参的数量,属性,量纲是否正确
- 是否引用了与当前入口点无关的形参
- 是否改变了某个原本仅为输入值的形参
- 全局变量的定义在模块间是否一致
- 常数是否以实参形式传递过
其他检查
- 在交叉引用列表中是否存在未引用过的变量
- 属性列表是否与预期的相一致
- 是否存在“警告” 或“提示”信息
- 是否对输入的合法性进行了检查
- 是否遗漏了某个功能
同行评审: 依据程序整体质量、可维护性、可扩展性、易用性和清晰性对匿名程序进行评价的技术。
4 测试用例的设计
推荐不走:先黑盒测试,再白盒测试
测试 | 内容 |
---|---|
黑盒测试 | 等价类划分,边界值分析,因果图分析,错误猜测 |
白盒测试 | 语句覆盖,判定覆盖,条件覆盖,判定/条件覆盖,多重条件覆盖 |
5 模块(单元)测试——白盒测试
-
测试用例的设计:
NEED:模块的规格说明(输入、输出、参数、功能)、模块的源代码
过程:使用一种或多种白盒测试方法分析模块的逻辑结构,然后使用黑盒测试方法对照模块的规格说明以补充测试用例。 -
将模块组装成工作程序的方式:增量测试、非增量测试
增量测试(集成):先将下一步要测试的模块组装到测试完成的模块集合中,然后再测试。
增量测试方法:自顶而下、自底而上
测试单独的模块需要驱动模块和N个桩模块
驱动模块模拟输入,桩模块模拟调用
驱动模块可以交迭地调用被测模块(不用设计多个版本)
开发驱动模块容易
结论:增量测试优
- 增量测试:自顶向下测试和自底向下测试
“自顶向下的测试” 约等于 “自顶向下的开发” 不等于 “自顶向下的设计”
自底向上的测试 不是 非增量测试
下一个模块,一定要事先进行了测试
自顶向下的测试:
优点 | 缺点 |
---|---|
很快发现程序顶层缺陷 | 必须开发桩模块 |
一旦引入I/O功能,提交测试用例会更加容易 | 桩模块比最初的表现更复杂 |
早期的程序框架可以演示,激发积极性 | 在引入I/O功能之前,提交测试用例复杂 |
创建测试环境困难,甚至无法实现 | |
观察测试输出困难 | |
让人误解测试和设计可以交迭进行 | |
会导致特定的模块测试的完成延后 |
- 注意认真编写桩模块
- 尽早加入关键模块
- 尽早加入I/O模块
- 由于输入或输出距离被测模块较远,很难使用全部用例
- 无法想象中间模块执行的实际情况
- 较底层与较高层往往互通资源
自底向上的测试:
优点 | 缺点 |
---|---|
很快发现程序底层缺陷 | 必须开发驱动模块 |
观察测试输出比较容易 | 直到最后一个模块添加进去,程序才形成一个整体 |
测试环境比较容易建立 |
- 早期没有程序框架
- 可以建立所有测试环境
6 更高级别的测试
6.1 功能测试
功能测试:发现程序与其外部规格说明之间存在不一致的过程。方法见 4.测试用例的设计
6.2 系统测试
系统测试:企图说明程序作为一个整体是如何不满足其目标的过程。利用用户文档和程序目标
分类 | 说明 | 方法 |
---|---|---|
能力测试 | 确保程序的目标功能实现 | 对比目标和用户文档 |
容量测试 | 发现处理大容量数据时的程序异常 | |
强度测试 | 发现在大规模负载、高强度不间断持续的数据处理中的异常 | 适用于可变负载下运行的程序,例:基于web的应用程序。同样的错误可能发生在现实的、强度稍低的环境中 |
可用性测试/用户体验测试 | 评估最终用户在使用软件并于软件交互时的可用性问题 | 发动最终用户在真实环境下对应用程序进行测试 |
安全性测试 | 企图破坏程序的安全防线 | 研究类似系统中已知的安全问题。基于web的应用程序常常比绝大多数程序所需的安全测试级别更高 |
性能测试 | 评估程序的响应时间以及吞吐量瓶颈 | |
存储测试 | 确保程序可以正确处理其对存储的需求,包括系统的存储和物理上的存储 | |
配置测试 | 检查程序是否能在推荐配置上流畅运行 | 至少每一种类型的设备,以最大最小的配置来测试程序 |
兼容性/转换测试 | 评估新版本是否能兼容老版本 | |
安装测试 | 确保能够在所有支持的平台上安装软件 | |
可靠性测试 | 评估软件是否能达到规格说明中的运行时长和MTBF要求(平均故障间隔时间) | |
可恢复性测试 | 测试系统恢复相关功能是否按设计要求实现 | MTTR(平均恢复时间) |
服务/可维护性测试 | 评估系统是否拥有良好的数据处理和日志机制,以备技术支持和调试之需 | 例:调试明显问题的平均时间 |
文档测试 | 校验所有的用户文档是否准确 | 将文档中描述的任何范例编成测试用例,提交给程序 |
过程测试 | 对软件系统操作或维护所需涉及的流程进行评估和确定 | 应由不相关的人测试过程 |
7 可用性(用户体验测试)
- 是否每个设计都考虑到了最终用户的理解力、教育背景以及环境压力
- 程序的输出是否有意义,没有侮辱性的词语,以及含糊不清
- 提示错误的诊断信息是否直白易懂
- 用户界面上是否保持概念的一致,内部的连贯,语法的一致;是否符合约定的使用习惯、语义和句法规律、格式、样式以及缩写习惯。
- 需要高精度性和准确度的软件系统是否提供了足够有效的输入验证。
- 系统是否包含太多不会被使用的选项
- 对于用户的输入,系统是否能及时做出反应
- 程序操作是否轻易上手
- 软件设计是否可以有助于用户精确输入,测试可以统计出哪些属于可以被用户订正的错误,而哪些会导致软件异常。
- 用户的操作可以轻松重复吗
- 用户是否确定能够在众多功能和菜单中来回切换而不发生意外。
- 软件的功能实现是否达到了设计规格要求。
数据采集的方式: 发声思考、远程测试、眼球追踪
可用性调查问卷:是/否, 真/假, 某种程度的同意/反对
8 调试
调试是一个包含两个步骤的过程,从执行了一个成功的测试用例、发现了一个问题之后开始。第一步,确定程序中可疑错误的准确性质和位置;第二步,修改错误。
暴力调试
- 利用内存信息输出调试
- 根据一般的“插入打印语句”调试
- 使用自动化的调试工具进行调试
归纳法调试
演绎法调试
回溯法调试
测试法调试
8.6 调试的原则
定位错误的原则:
- 动脑筋
- 如果遇到了僵局,就留到稍后解决
- 如果遇到了困境,就把问题描述给其他人听
- 仅将调试工具作为第二种手段
- 避免使用试验法—仅将其作为最后的手段
cd
修改错误的技术:
- 存在一个缺陷的地方,很有可能还存在其他缺陷
- 应纠正错误本身,而不仅是其症状
- 正确纠正错误的可能性并非100%:一个严格的回归测试计划可以确保对某个错误的修改没有在程序的其他位置引入另外的错误。
- 随着程序规模的增加,正确修改错误的可能性反而降低
- 应意识改正错误会引入新错误的可能性
- 修改错误的过程也是临时回到设计阶段的过程
- 应修改源代码,而不是目标代码
9 敏捷开发模式下的测试
敏捷开发提倡迭代式和增量式的开发模式。
客户是敏捷的关键环节,也就是说,如果没有客户的参与,敏捷方法等同失败。
敏捷测试依赖于自动化测试
极限编程(eXtreme Programming, XP)与测试
XP模型除了需要客户参与之外,还高度依赖模块的单元和验收测试。
在XP方法中,我们必须首先生成单元测试用例,然后才编写代码通过测试。