软件测试技术
软件测试技术
绪论:
软件测试定义两面性:
正向观点:测试是为了验证软件是否符合用户需求,即 验证软件产品是否能正常工作 。
逆向观点:一个成功的测试是 发现了至今未发现的错误 的测试。是为了证明程序有错,而不是证明程序无错误。
缺陷定义和缺陷类型
缺陷定义:程序员犯了 错误 (mistake) ,错误在程序或软件中就表现为 缺陷(defect/fault) 。运行带有缺陷的软件或程序,在运行过程中出现与预期不同或不可接受的内部状态,出现 故障(error) ,外部可能观察到 失效/失败(fail/failure) 。
Bug通常是缺陷导致的故障,一个缺陷可能导致不同的Bug。
Bug:软件 = 程序+文档,Bug是软件中(包括程序和文档)不符合用户需求的问题。类型:完全没有实现的功能、功能或性能问题或差异、多余的功能。
软件测试的基本原则
- 测试应该尽早启动,尽早介入
- 软件测试应该追溯需求(测试》编码》设计》需求分析)
- 不可能执行穷尽测试
- Zero bug 与Good Enough(理想状态,既充分也不多余)(没有bug不代表足够好,不可能没有bug,够好就行)
- 缺陷存在群集现象
- 缺陷具有免疫性(杀虫剂悖论)
- 不存在缺陷的理论(测试无法显示潜伏的软件缺陷)
软件测试分类
测试需求分析
测试需求分析是测试设计和开发测试用例的基础。主要目的:依据需求文档提取测试点,根据测试点来编写测试用例。
软件测试工作流程
- 制定测试目标和依据
- 测试需求分析:确定测试对象、测试范围
- 制定测试计划:测试工作量估算、资源估算、进度安排、风险评估、制定策略
- 设计测试用例,开发测试工具或脚本
- 执行测试
- 测试结果分析
- 提交测试报告
测试需求分析过程
- 了解项目的背景、产品价值,要解决什么业务问题 ;分析业务需求,确定测试目标
- 了解用户是谁,用户所关心的问题 ;分析用户需求
- 确定待测软件的功能特性,可以从整体到局部,从上到下,逐层分解,形成待测试的功能列表
- 确定待测软件的非功能特性,基于本系统的特点而需特别关注的质量属性
- 确定测试项的优先级
软件测试计划
测试计划内容
软件测试计划是 指导测试过程的纲领性文件 ,描述测试活动的范围、方法、策略、资源、任务安排和进度等,并确定测试项、哪些功能特性将被测试、哪些功能特性将无需测试,识别测试过程中的风险。
内容主要集中在测试目标和需求说明、测试工作量估算、测试策略、测试资源配置、进度表、测试风险等。
软件测试设计——黑盒测试
等价类划分:
方法:完全不考虑程序的内部结构,只根据程序规格说明书对输入范围进行划分。所有可能的输入数据,即程序输入域划分为若干个互不相交的子集,称为 等价类 ,然后从每个等价类中选取少数具有代表性的数据作为测试用例,进行测试。
在分析需求规格说明的基础上 划分等价类 ,列出 等价类表 。
等价类是某个输入域的子集,在该子集中每个输入数据的作用是等效的。
分为 有效等价类 (合理的、有意义的输入
数据构成的集合)和 无效等价类
在规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类。
在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)。
用例设计原则:
- 建立等价类表,列出所有划分出的等价类:
- 为每个等价类规定一个唯一的编号;
- 设计一个新的测试用例,使其 尽可能多地 覆盖 尚未覆盖的有效等价类
- 重复3,最后使得所有有效等价类均被测试用例所覆盖;
- 设计一个新的测试用例,使其 只覆盖一个无效等价类 。
- 重复5,使所有无效等价类均被覆盖。
例如:
因果图回溯
基本符号(因与果连接):
约束符号(因与因,果与果连接):
步骤:
- 分析软件规格说明文档描述的哪些是原因( 输入条件 ),哪些是结果( 输出条件 )。原因常是输入条件或输入条件的等价类,结果是输出条件。
- 分析程序规格说明的描述中的语义内容,将其表示成连接各个原因与各个结果的“因果图”。
- 标明 约束条件 。在因果图上标上哪些不可能发生的因果关系,表明约束或限制条件。
- 根据因果图, 创建判定表 ,将复杂的逻辑关系和多种条件组合很具体明确的表示出来。
- 把判定表的每一列作为依据设计测试用例。
实例:
判定输入、输出、中间节点
得到因果图:
生成判定表:
回溯:
- 选择一个果作为当前状态
- 对因果图进行回溯,查找导致该果为1的所有因的组合
- 在判定表中为每个因的组合生成一列
- 对于每种“因”的组合,判断所有其他“果”的状态,并放置在每一列中。
要点:
若条件为 或 ,取值为1时,不考虑a=b=1的情况;取值为0时,考虑都不满足的组合。
若条件为 且 ,取值为1时,考虑都满足的组合;取值为0时,都不满足的情况仅需考虑一种。
组合测试方法
大部分缺陷是在两个变量取值冲突的测试时被发现的。
方法:正交实验法
优势:两大优越性,即“均匀分散,整齐可比”。特性中有任意一条不满足,就不是正交表。
正交表选择:例如以下L9(3.4.)
9:行数,正交表中的行的个数,即试验的次数,也是通过正交实验法设计的测试用例的个数。
3:水平数:任何单个因素能够取得的值的最大个数,即要测试功能点的输入值。即一个输入最多有多少种情况。
4:因素数:正交表中列的个数,要测试的功能点,即有多少种输入。
选择正交表:
(1)确定因素,这里的因素是指对软件运行结果有影响的输入
(2)确定因素的取值范围或集合(该步是为步骤3做准备的),因素的取值范围是指软件输入的取值范围或集合以及可用的硬件资源。
(3)确定每个因素的水平,根据因素的取值范围或集合 ,采用等价类划分、边界值分析以及其他软件测试技术,在每个因素的取值范围或集合内挑选出有效等价类、无效等价类、正好等于、刚刚大于或刚刚小于边界值等有代表性的测试值。
(4)选择正交表,根据确定的因素和水平 ,选择适合的正交表。
若之前确定了因素数=3,水平数=2;则在选择正交表时,因素数>=3且水平数>=2的情况下,行数取最少的一个,即试验次数最少的一个。
测试执行缺陷管理
正确测试用例描述
正确缺陷描述
完整缺陷描述的重要因素:
步骤 :提供了如何重复当前缺陷的准确描述
期望结果 :与测试用例标准或设计规格说明书或用户需求等一致,达到软件预期的功能。是验证缺陷的依据。
实际结果 :实际执行测试的结果,不同于期望结果,从而确认缺陷的存在。
缺陷报告——缺陷描述的基本要求。
- 状态
激活或打开: 问题还没有解决 ,等待处理
已修正或修复:已被开发人员检查、修复过的缺陷,通过单元测试,认为已解决 但还没有被测试人员验证
关闭或非激活:测试人员 验证后,确认缺陷不存在 的状态
重新打开 :测试人员 验证后,还依然存在 的缺陷,等待开发人员再次修复
推迟:可以在 下一个版本解决
保留:技术原因或第三种软件的缺陷,开发人员 不能修复
不能重现: 开发不能复现软件缺陷 ,需要测试人员检查缺陷复现的步骤
需要更多信息:开发 能复现 软件缺陷, 但需要一些信息
- 严重性
致命的(fatal)、严重的(critical)、一般的(major)、微小的(minor)
- 优先级
缺陷被修复的紧急程度。
注意:不是每个软件缺陷都需要开发人员修复。
分类:立即解决、高优先级、正常排队、低优先级
一般严重程度高的软件缺陷具有较高的优先级,但是不一定;严重程度低的优先级也不一定低。
某些严重的软件缺陷只在非常极端的条件下产生。
- 其他属性
缺陷标识;缺陷产生可能性;缺陷来源;缺陷原因
软件缺陷生命周期
定义:是一个软件缺陷被发现、报告到这个缺陷被修复、验证直至最后关闭的完整过程。
参与人员:各类开发人员一起参与、协同测试的过程。
基本周期:发现》打开》修复》关闭;测试人员》开发人员》测试人员
发现-打开:测试人员找到软件缺陷并将软件缺陷提交给开发人员。
打开-修复:开发人员再现、修复缺陷,然后提交给测试人员去验证。
修复-关闭:测试人员验证修复过的软件,关闭已不存在的缺陷。
处理了流程:
已经关闭的Bug可以重新打开(Reopen),即Bug可以死而复生;
白盒测试
逻辑覆盖方法
要求:能够分析代码段的逻辑条件
语句覆盖法: 设计若干测试用例,运行被测程序,使程序中的每个可执行语句至少被执行一次。 能发现一般语句的错误,但不能发现其中的逻辑错误。
判定覆盖DC: 设计若干用例,运行被测程序,使得程序中 每个判断的取真分支和取假分支 至少经历一次,即判断真假值均曾被满足。(真假判断各一次)
(a, b ,c)= (1, 1, 2)——T, T
(a, b ,c)= (-1, 1, 0)——F,F
条件覆盖CC: 设计若干用例,执行被测程序,使 每个判断 中每个条件的可能取值至少满足一次。(大小条件全都有一次)
(a, b ,c)= (2, -1, 0)—— T1, F2, T3, F4——F,T
(a, b ,c)= (-1, 1, 2)—— F1, T2, F3, T4——F,T
判定-条件覆盖CDC: 设计足够的测试用例,使得判断条件中的所有条件可能取值至少执行一次,同时,所有判断的可能结果至少执行一次。
(a, b ,c)= (2, 1, 2)—— T1, T2, T3, T4 —— TT——TT
(a, b ,c)= (-1, 0, 1)—— F1, F2, F3, F4 —— FF——FF
条件组合覆盖MCC:
设计足够的测试用例,使得判断中每个条件的 所有可能组合至少出现一次 ,并且每个判断本身的判定结果也至少出现一次。 覆盖了所有组合,但覆盖路径有限
修正条件/判定覆盖MCDC: (屁事多,还不好理解)
每个判定的所有可能结果至少能取值一次;
判定中的每个条件的所有可能结果至少取值一次;
一个判定中的每个条件曾经 独立地 对判定的结果产生影响;
每个入口和出口至少执行一次。
基本路径测试
要求:能够分析代码段绘制控制流图、计算环路复杂度、并设计线性无关路径;
基本路径覆盖的设计步骤 :
依据代码绘制流程图(只有空圈和箭头)
控制流图:
菱形框:表示判定条件, 内无复合条件 ;
汇聚处(实心圆):在选择或者是多分支结构中分支的汇聚处,没有执行语句也添加一个汇聚节点;
简化:
确定控制流图的圈复杂度
圈复杂度:代码逻辑复杂度的度量,提供了被测代码的路径数量。复杂度越高出错的概率越大。
V(G) = 连线数量 - 节点数量 + 2= 判断节点数目 + 1 = 区域数量
例如:上图为V(G) = 4
确定线性独立路径的基本集
独立路径: 至少引入一系列新的处理语句或条件的任何路径。
基本集: 由独立路径构成的集合。由基本集导出的测试用例,保证每行代码语句至少被执行一次;基本集合不一定唯一。
例如上图:
设计测试用例覆盖每条基本路径
循环测试
要求:能够对循环结构进行测试分析
循环化简:
有时无法实现路径覆盖。考虑循环化简,限制循环次数。
- 对循环机制进行简化,舍掉一些次要因素,极大地减少路径数量,使得覆盖有限的路径成为可能。
- 循环化简,即限制循环的次数。无论循环的形式和实际执行循环体的次数多少, 只考虑循环1次 和 0次 两种情况,即 进入循环 和 跳过循环 两种情况
循环分类:
简单循环(迭代次数n)
• 完全跳过循环
• 只经过循环一次
• 经过循环m( m < n )次
• 分别经过循环n-1, n, n+1 次
嵌套循环
在最里面的循环完成前面所述的简单循环测试,同时设定外部循环的最小迭代次数,逐步向外循环进行直到所有循环被测试。
串行连接的循环
独立循环可以分别看成简单循环测试;
依赖性循环可以看成是嵌套循环。
单元测试和集成
单元测试的任务
模块独立执行路径测试
检查每一条独立执行路径的测试,并保证每条语句被至少执行一次。
局部数据结构测试
检查局部数据结构完整性
模块接口测试
检查模块接口是否正确
单元边界条件测试
检查临界数据处理的正确性
单元容错测试
预设的各种出错处理是否正确有效。
驱动程序和桩程序
运行单元程序有时需要基于被测单元的接口,开发相应的驱动模块和桩模块。
驱动模块:对 底层或子层模块进行测试 所编写的调用这些模块的程序, 自底向上法
桩模块:对 顶层或上层模块进行测试 时所编写的替代下层模块的程序, 自顶向下法 ;由被测模块调用。
集成测试模式
非渐增式测试模式 先分别测试每个模块,再把所有模块按设计要求放在一起结合成所要的程序,如大棒模式(先是对每一个子模块迚行测试(单元测试阶段),然后将所有模块一次性的全部集成起来迚行集成测试。不推荐在任何系统中使用,适合在规模较小的应用系统中使用)。
特点:可以并行测试。
渐增式测试模式 把下一个要测试的模块同已绊测试好的模块结合起来迚行测试,测试完以后再把下一个应该测试的模块结合迚来测试。
特点:测试更彻底但需要较多的机器时间。
自顶向下法:
对 主控模块 迚行测试,测试时用 桩程序 代替所有直接附属于主控模块的模块。结合下一个模块的同时迚行测试; 为了保证加入模块没有引迚新的错误,可能需要迚行 回归测试 。
自底向上法:
把底层模块组合成实现某个特定的软件子功能的族,写一个驱动程序(用于测试的控制程序),协调测试数据的输入和输出。
混合策略:
以上两种都要
三明治集成方法:
优点:将自顶向下和自底向上的集成方法有机地结合起来,不需要写桩程序。
缺点:在真正集成之前每一个独立的模块没有完全测试过。
改进的三明治集成方法,不仅自两头向中间集成,而且保证每个模块得到单独的测试,使测试迚行得比较彻底 。
系统测试
系统测试内容
功能测试:
- 单元功能测试:保证所测试的每个独立的模块的功能正确,从输入条件和输出结果来判断是否满足程序的设计要求。
- 系统功能测试:考虑模块间的相互作用,考虑系统的应用环境;衡量标准是实现产品规格说明书上所要求的功能;特别地,模拟用户从头到尾的业务测试,确保系统可以完成实现设计的功能,满足用户实际业务需求。(系统集成中或之后)
回归测试:
见下单员
性能测试:
见下下单员
其他非功能性测试。
回归测试
回归测试是为了 发现回归缺陷 而进行的测试。定义:对软件的新版本测试时,重复执行上一个版本测试时的用例。
回归缺陷 :一旦程序某些区域被修改了,就可能影响其它区域,导致受影响的区域出现新的缺陷。
既有黑盒测试的回归,也有白盒测试的回归。
性能测试(负载压力测试)
用来保证产品发布后系统的性能能够满足用户需求,是为了发现系统性能问题或获取系统性能相关指标而进行的测试。(一般在真实环境、特定负载)
测试目标:
获取系统性能某些指标数据;
为了 验证 系统是否达到用户提出的性能指标;
发现系统中存在的 性能瓶颈 ,优化系统的性能。
产品生命周期中负载压力测试计划:
需求分析中充分关注负载压力性能
在设计中得到负载压力性能指标
开发阶段创建负载压力性能测试环境
验收阶段在多等级范围内测试幵调优
运行阶段持续监控系统负载压力性能
测试指标:
用户对各项指标提出的明确需求,如果用户没有提出性能指标,则根据用户需求、测试设计人员的经验来设计各项测试指标。
负载压力测试:
在一定约束条件下测试系统所能承受的并发用户量、运行时间、数据量,以确定系统能承受的最大负载压力。
并发性能测试(要点):逐渐增加开发用户数负载,直到系统出现性能瓶颈或者崩溃为止。(破坏性压力测试:通过不断加载的手段,快速造成系统的崩溃,让问题尽快地暴露出来)
疲劳强度测试:采用系统稳定运行情况下能够支持的最大负载(最大开发用户数),持续长时间运行,通过综合分析来确定系统处理最大工作量强度性能的过程,以发现性能问题。(渗入测试、峰谷测试)
大数据量测试:针对某些系统存储、传输、统计、查询等业务进行大数据量测试。
负载测试&压力测试:
负载测试:过逐步增加系统负载,测试系统性能的变化,并最终确定在满足性能指标的情况下,系统能承受的最大负载量的测试。
压力测试:逐步增加系统负载,测试系统性能的变化,最终确定在什么负载条件下系统性能处于失效状态,以此来获得系统能提供的 最大服务级别 的测试。了发现在什么条件下系统的性能会 变得不可接受。