type
status
date
slug
summary
tags
category
icon
password
这里先摆上一张重点图,但是这个重点图跟下面的小标题对不上)
6.1 软件质量相关概念
6.1.1 质量相关概念
- 质量控制
- 质量控制的定义:审查产品相关的各个方面质量的过程
- 质量控制的内容(也就是需要审查产品的哪些方面)
- 元素:过程控制、作业管理
- 能力:知识、技能、经验、资历
- 软要素:人员廉洁、文化、团队合作
- 质量控制的目标:建立体系并确保按照体系运作,以提供内外部的信任
- 质量保证
- 质量保证的定义:系统地监测和评估工程的各个部分,最大限度地提高最低质量标准
- 质量保证的内容(也就是质量保证需要去监测评估哪些方面):原料、文档、组件、产品、以及产品的管理、生产、检测等质量管理过程
- 质量保证的原则
- 适合用途原则:产品应当符合预期目标
- 一次成功原则:不合格的产品应该被淘汰
- 质量成本:追求质量过程或履行质量有关活动所引起的费用以及因质量不佳而引起的下游费用等所有费用
- 预防成本(就是预防质量不佳而产生的成本,对应质量成本概念中的前半部分)
- 评估成本(就是评估当前产品质量好坏而产生的成本,对应质量成本概念中的牵绊部分)
- 失效成本(就是质量不佳引起的下游成本,如在测试阶段因为质量不佳而导致的返工;交付之后发现质量不佳而导致的赔偿等,对应质量成本概念的后半部分)
6.1.2 软件质量相关概念
- 软件质量:明确表示软件产品是否符合功能性能需求,是否符合开发标准以及是否具有所有专业开发软件所具有的隐性标准
- 影响软件质量的关键点
- 符合明确规定的功能性能需求
- 符合开发标准
- 具有所有专业开发软件所具有的共性、隐性特点,如易用性和可维护性
- 软件质量保证:依据一定的开发标准、过程和步骤对软件产品质量进行评估的活动
- 软件质量保证的方法(形式)
- 审查:确保符合既定的开发标准
- 监督:根据文档中描述的过程和操作步骤,确保执行过程采取适当的步骤和操作方式
- 审计:确保在软件开发过程中采取了恰当的质量控制措施,以符合相应的过程和标准
6.1.3 软件评审
- 软件评审:在一个阶段或者会议期间对软件产品进行审核,由开发人员、管理人员、客户和有关各方对软件产品进行评估和批准
- 软件评审的形式
- 同行评审:由同行评审技术的含量和质量
- 管理评审:由管理人员代表总结当前工作,并安排后续工作
- 审计评审:由有关各方评价软件产品的规范性,标准化程度以及合同履行情况
6.1.4 软件可靠性
- 软件可靠性:指在规定时间内,在特定的环境下软件无错执行的概率
- 软件可靠性的评估标准
- 可靠性:指避免或检测重大错误的能力
- 可靠性的衡量指标
- 平均失效时间
- 平均维修时间
- 可用性:指在某一个时间点程序按照需求执行的概率
- 可用性的衡量指标
- 失效在维护中的占比
6.2 软件测试策略
6.2.1 软件测试策略概述
软件测试策略含义
- 软件测试策略:软件测试策略为软件开发人员、质量保证组织、和客户提供了一个路线图,规定了测试的主要步骤
- 为保证可行性,须考虑人力成本、时间和资源。故应结合:测试计划、测试用例设计、测试执行、测试结果数据的收集与分析
- 软件测试策略的要求
- 灵活性:保证有足够的可塑性足以应付所有的大软件系统
- 严格:保证对所有的项目过程都有合理的计划和跟踪管理
软件测试策略V模型
回忆一下过程模型中的V模型:V模型应该是瀑布模型的一个变种,反馈线是打到对应的阶段上的。如验收测试的反馈线是打到需求分析阶段的(因为验收是给用户使用,用户发现不合理当然要重新去审查用户之间提出的需求)。可以看出之前说的V模型是很强调测试的
而在软件测试中的V模型跟之前提到的软件过程模型中的V模型没什么区别
如下图:
注意:V模型在需求分析前面增加了一个用户需求,因为用户需求和需求分析阶段的需求可能是不一样的(因为可能存在用户表述不明,或者开发人员理解不到位的情况)
- V模型:V模型非常清楚的表明了测试过程中存在的不同级别,并且清楚的表示了这些测试阶段和开发过程中各阶段的对应关系(就是过程模型中的反馈线关系)
- V模型的测试阶段(跟前面说的测试阶段和开发阶段的对应关系有关)
- 单元测试:主要目的是测试各软件模块是否按照详细设计的规格说明正确运行
- 集成测试:主要目的是测试各软件模块间是否按照概要设计的说明协同工作
- 系统测试:主要目的是测试整个系统是否符合需求规格说明
- 验收测试:从用户的角度(也就是用户需求)出发,测试系统是否符合合同中的需求,以及系统是否符合业务上的需求
回归测试
- 回归测试:指有选择的对系统或其组件进行再测试
- 为什么需要进行回归测试?
- 软件测试时,如有缺陷修复、功能增加等,变化的部分需要再次进行测试(在测试阶段的,所以是说测试)
- 软件的修改可能会导致新的缺陷或者问题的出现,为了避免这些问题和缺陷,需重新测试(在其他阶段的,所以是说修改)
- 回归测试的方法:回归测试应尽量采用自动化测试
- 回归测试的范围:回归测试可以在所有测试级别(也就是测试阶段)中使用,应用于功能性测试和非功能性测试
- 缺陷再测试:重新进行所有发现故障的测试
- 功能改变的测试:对所有进行修改或修正的程序进行测试
- 新功能测试:测试新集成的程序
- 完全回归测试:测试整个系统
- 自动化测试(回归测试常采用的方法):将以人为驱动的传统测试转为机器执行的测试方法
- 自动化测试的步骤
- 测试需求分析,如果确定项目适合自动化测试就明确测试的范围、测试用例以及测试数据
- 定义测试所需的文件、结构等,其中重复使用的部分可抽取出来做封装,便于重用
- 使用脚本工具提供的录制功能生成脚本,然后手动编写脚本增加结构化调用、函数调用等
- 检查脚本的正确性,进行自动化测试
- 自动化测试的适用范围
- 回归测试,重复单一的测试造成了不必要的时间浪费和人力浪费
- 测试人员对程序的理解以及对设计文档的验证通常都需要借助于测试自动化工具
- 使用自动化测试有助于测试文档的生成以及版本的连贯性
- 自动化测试确定了测试用例的覆盖路径,确保测试用例对程序逻辑流程和控制流程的覆盖
软件测试策略注意事项
- 在着手开始测试之前,要对产品的需求进行量化(量化之后才能进行测试)
- 明确指出测试目标(做什么事都要有目标)
- 为每类用户建立描述交互场景的用例(设计测试用例)
- 建立一个强调“快速循环测试”的测试计划(多次测试,实际上就是多次回归)
- 设计一个能够测试自身是否“强壮”的软件(要保证测试软件本身强壮)
- 在进行测试之前,对软件进行有效的正式技术审核(要保证测试软件本身是正确的)
- 使用正式技术审核来评估测试策略和测试用例本身(要保证测试用例和测试策略是合理的)
- 为测试过程建立一种持续的改进方法(要进步捏)
软件测试策略基本步骤
这里的基本步骤只针对单元测试,集成测试和系统测试,因为验收测试可以说是测试阶段和交付阶段的衔接点了
- 计划与准备
- 制定计划
- 编写评审测试用例
- 编写测试脚本和准备测试环境
- 执行
- 搭建测试环境
- 构造测试用例
- 执行测试并记录问题
- 确认问题
- 撰写测试报告
- 返工、进行回归测试
6.2.2 单元测试
- 单元测试:单元测试是指对程序中的最小单元——程序模块进行正确性检验的测试活动
- 单元测试的方法:单元测试需要从程序本身的结构出发(所以是白盒)进行测试。不同模块之间可以平行独立地进行单元测试
- 单元测试的主要依据:详细设计(想想单元测试的反馈线是连到哪里的,也可以想想单元测试的目的是什么——测试程序模块是否按照详细设计的规格说明正确执行)
- 单元含义:在不同环境下单元的含义不同
- 面向过程:函数、过程等
- 面向对象:类、类中的方法等
- 单元测试的进入退出条件
- 单元测试的进入条件
- 被测代码通过编译链接
- 被测代码经过静态检查工具检查
- 被测代码经过至少一轮走读
- 单元测试用例经过审查
- 单元测试的代码写完并通过测试
- 单元测试的退出条件
- 所有测试用例全部通过
- 单元测试的覆盖率达到指定要求
- 单元测试未被执行的代码经过正式审查
- 单元测试的测试内容(就是对一个模块需要测试哪些部分)
- 模块接口
- 数据流测试(跟其他的模块之间的接口)
- 调用本模块的输入参数是否正确(输入参数是否正确)
- 本模块调用子模块时输入给子模块的参数是否正确(输出参数是否正确)
- 全局量的定义在各模块中是否一致(全局)
- 内外存交换测试(跟硬件或者说跟计算机之间的接口)
- 文件属性是否正确
- OPEN与CLOSE语句是否正确;
- 缓冲区容量与记录长度是否匹配;
- 在进行读写操作之前是否打开了文件;
- 在结束文件处理时是否关闭了文件;
- 正文书写/输入错误
- I/O错误是否检查并做了处理。
- 局部数据结构
- 局部数据结构测试的测试内容
- 不正确或不一致的数据类型说明
- 使用尚未赋值或尚未初始化的变量
- 错误的初始值或错误的缺省值
- 变量名拼写错或书写错误
- 全局数据对模块的影响
- 独立路径
- 路径测试的内容
- 重要路径:对程序的重要执行性路径进行测试
- 计算、控制流路径:检查由不正确的计算、不正确的比较以及不正常的流程控制而导致的错误
- 基本路径、循环:对程序的基本执行路径和循环进行测试
- 边界条件(等价类划分与边界值,虽然这俩方法应该是算黑盒测试的)
- 流边界(逻辑边界):考虑出现控制流或者数据流中等于、大于、小于确定比较值时出现错误的可能性。对这些边界条件要仔细选择用例加以测试
- 关键路径(时间边界):如果对模块的运行速度有要求的话,还需要进行专门的关键路径测试,以找寻在最坏情况和平均意义下影响模块运行时间的因素
- 出错处理
- 出错的描述是否难以理解
- 出错的描述是否能够对错误定位
- 显示的错误与实际的错误是否相符
- 对错误条件的处理正确与否
- 在对错误进行处理之前,错误条件是否已经引起系统的干预等
- 单元测试用例设计
- 依据:详细设计说明书和源程序清单
- 了解:模块的IO条件和逻辑结构
- 手段:以白盒测试为主,黑盒测试为辅(因为单元测试的方法是要从程序的结构出发,所以这里是白盒测试为主)
- 结果(或者说如何处理当前用例测试的结果):对合理、不合理输入的鉴别,比较预计和实际的结果
- 单元测试环境搭建:在程序中模块并非独立的成分,在进行测试时需要考虑模块与外界之间的联系,需使用一些辅助模块进行模拟
- 驱动模块:模拟被测模块的上一级模块,相当于被测模块的主函数
- 桩模块:模拟被测模块调用的模块,但是并不是软件产品的部分
- 驱动模块和桩模块如下图:
6.2.3 集成测试
- 集成测试的含义:将软件模块集成起来进行测试(别名:子系统测试、组装测试、部件测试)
- 集成测试的目的:检查如两个模块单独运行时正常,但是集成起来运行出错的情况(或者按照上面目的来讲:测试各部件集成起来之后是否按照概要设计的说明协同工作)
- 集成测试的方法
- 自顶向下的集成方法
- 自底向上的集成方法
- SMOKE方法
- 自顶向下的集成方法:该方法按照程序的系统结构,沿控制层次自顶向下进行集成
- 自顶向下集成方法的优点
- 可以较早验证主要的功能点和控制点进行检验(因为会先检查最顶层,也就是最关键的控制层)。按深度方向还可以优先检验某一个功能
- 自顶向下集成方法的缺点
- 桩模块的开发量较大(因为是从顶层开始的,检查上层的时候就需要去编写桩模块)
- 自顶向下集成方法的适用场景
- 控制结构清晰
- 高层接口较稳定
- 底层接口未定义或者不清晰
- 接口控制组件有较大的技术风险,希望尽早被验证
- 希望尽早看到系统的功能行为
- 广度优先的自顶向下集成方法如下:
深度优先的自顶向下集成方法如下:
- 自底向上的集成方法:从软件结构的最底层开始,按照接口的依赖关系逐层向上进行集成
- 自底向上方法的优点:被测模块调用的模块在之前都已经经过测试,所以不需要装模块
- 自底向上方法的缺点:必须编写驱动程序;对缺陷的定位能力不如自顶向下(因为自顶向下一定是刚加进来的模块出现了问题,自底向上也是,但是自底向上加进来的就不是模块,而是一组模块,所以定位能力会比自顶向下差)
- 自底向上方法的适用场景(说白了就是谁稳定、谁先被写完就先测谁)
- 高层接口变化频繁
- 底层接口较为稳定
- 底层的接口组件较早完成
- 自底向上的集成方法示例如下:
- 自顶向下和自底向上集成方法的注意事项:在实际测试中,常常结合自顶向下和自底向上两种集成测试方法。如对一个已经编写完成的模块进行测试时:
- 若被测模块的子模块没有完成,就采用自顶向下的集成方法,编写桩模块之后再进行测试
- 若被测模块的主模块没有完成,就采用自底向上的集成方法,编写驱动模块之后再进行测试
- SMOKE方法(前面两种实际上是按照一定的顺序来进行的测试,但是SMOKE方法是有什么就拿什么来进行集成)
- SMOKE方法的基本思想:将已经转化为代码的组件集成为构造。一个构造包括所有的数据文件,可复用模块以及完成一个或多个功能所必须的工程化构建
- SMOKE方法的目标:设计暴露影响构造完成其功能的错误的测试,以发现有可能造成项目延迟的业务阻塞错误
- SMOKE方法的方法:每天将该构造和其他的构造以及软件产品进行集成,进行冒烟测试(既可以采用自顶向下的集成测试方法,也可以采用自底向上的集成测试方法)
- 集成测试用例的设计
- 通过性测试(就是这些设计的用例预计的结果应该是正确的)
- 等价类划分
- 场景分析法
- 状态图法
- 失效性测试(就是这些设计的用例预计的结果应该是错误的)
- 边界值分析
- 错误猜测法
- 因果图法
- 状态图法
- 覆盖率
- 接口覆盖率(覆盖了所有模块的接口中的哪些接口)
- 接口路径覆盖率(覆盖了某个接口中的哪些路径)
- 注意接口
- 显式接口:函数调用
- 隐式接口:消息,网络协议等
6.2.4 系统测试
- 系统测试的含义:从用户使用(也就是考虑需求规格说明书的内容,所以主要方法是黑盒测试)的角度测试系统,将通过了集成测试的系统放在真实的运行环境中进行测试
- 系统测试的目的:功能的确认和验证(或者上面所说的:测试整个系统是否符合需求规格说明)
- 系统测试的方法:黑盒测试
- 系统测试的必要性:系统测试是软件开发过程中必不可少的步骤,是软件质量保证的最重要的环节
- 系统测试的内容:
- 面向:外部输入层测试。如果不做外部输入层测试,那么外部输入层和接口层转换的那部分代码就没有得到测试
- 面向:系统中所有的模块之间相互协调(这是单元测试和集成测试没有做的,集成测试只是将一部分模块合在一起测试,并没有将所有模块集成在一起测试)
- 系统测试的角度:需求规格说明(因为是软件开发团队从用户使用的角度触发进行的测试。单元测试和集成测试的角度就是设计规格说明)
- 系统测试的内容
- 功能测试(测试需求规格说明中的功能需求):在规定的时间内对系统的所有功能进行测试,验证软件系统是否有严重的错误
- 功能测试的方法:黑盒测试(系统测试一般用的都是黑盒测试,因为是从用户角度出发的)
- 功能测试中的错误类型
- 功能错误/遗漏
- 界面错误
- 数据结构或外部数据库访问错误
- 性能错误
- 初始化错误
- 性能测试:检查系统是否符合需求规格说明中的性能要求。通常与压力测试结合进行(压力也算是性能的一种),软件硬件测试同时进行
- 测试内容
- 相应时间
- 吞吐量
- 辅助存储区
- 压力测试:测试在系统运行环境不正常乃至出现故障的情况下,系统能运行到何种程度的测试
- 压力测试的方法
- 提高输入速度的量级
- 设计占用最大存储量或者其他资源的用例进行测试
- 设计会在虚拟内存管理机制中引起“颠簸”的用例进行测试
- 设计会对磁盘内存中常驻数据进行过度读写的用例进行测试
- 敏感性测试:是压力测试的一个变种。在程序的有效数据范围内的一个小范围内的数据可能引起极端的或者不稳定的错误处理,或者导致程序的性能下降
- 恢复测试:是为了证实在克服了硬件障碍后,系统能否恢复运行并且不受影响
- 恢复测试的手段:人工干预
- 恢复测试的内容
- 系统能否检测到硬件故障
- 发现硬件故障之后系统能否启用备用硬件
- 发生硬件故障时系统能否保存当前正在进行的作业以及系统状态
- 硬件故障恢复后系统能否从上一次无错状态处继续进行作业
- 掉电测试:电源中断后,系统能否保存当前正在进行的作业以及系统的状态;恢复电源的时候系统能否从断点处继续进行作业
- 安全测试:是为了测试系统中已经存在的安全性、保密性措施是否发挥作用,有无漏洞
- 对软件系统的主要攻击方法
- 正面、侧面或背面攻击系统中易受损坏的那些部分;
- 以系统输入为突破口,利用输入的容错性进行正面攻击;
- 申请和占用过多的资源压垮系统,以破坏安全措施,从而进入系统;
- 故意使系统出错,利用系统恢复的过程,窃取用户口令及其它有用的信息;
- 通过浏览残留在计算机各种资源中的垃圾(无用信息),以获取如口令,安全码,译码关键字等信息;
- 浏览全局数据,期望从中找到进入系统的关键字;
- 浏览逻辑上不存在,但物理上还存在的各种记录和资料等
- 文档测试、易用性测试、配置测试、本地测试等
6.2.5 验收测试
验收测试概念
- 验收测试的概念:完成系统测试之后,交付产品之前进行的测试活动
- 验收测试的目的:确保软件产品准备就绪
- 验收测试的时间节点(实际上从定义中就可以得出):系统测试以及软件配置审查之后
- 验收测试的人员:以用户为主(因为是给用户验收的)、开发人员、质量保证人员
- 验收测试的内容:除了功能性能以外,还有可维护性、可移植性、兼容性,错误的恢复能力等
- 验收测试的数据:实际生产的数据
验收测试过程
- 了解软件的质量要求和验收要求
- 编制《验收测试计划》《项目验收准则》
- 测试和测试用例设计
- 测试环境搭建
- 测试实施
- 测试结果分析
- 撰写测试报告
验收测试形式
- 根据合同的验收测试
- 系统测试子集再测试
- 用户验收测试
- 客户验收测试
- 最终用户验收测试
- 现场测试
- α测试:用户在开发环境、模拟用户在模拟的实际环境中进行的测试(就是用户还在开发环境上进行使用)
- 目的:评价FLURPS特性(功能、局域性、易用性、可靠性、性能和支持),尤其是界面和特色
- 原因:交付后,用户的实际使用程序是无法预测的(因为用户的环境跟开发环境可能不一样,会导致使用的程序出现不同的行为,所以α测试就是为了去预测用户的环境的)
- 开始时间:软件产品编码结束后;集成测试之后;系统测试过程中软件产品已经达到了一定的稳定性和可靠性
- β测试
- β测试的人员:多个用户在实际应用环境下使用软件产品,并将错误信息反馈给开发者
- β测试的形式:开发者通常不在现场,用户在开发者无法控制的场景下进行软件现场应用
- β测试的步骤:用户记录所有问题(主观的,正确的),定期向开发者报告
- β测试的目的:评估软件产品的FLURPS特性,着重于产品的支持性
- β测试的开始时间:α测试达到一定的可靠程度,是测试的最后阶段,此时所有的手册文本全部定稿
测试停止标准
软件是无法进行完全测试的,所以这里需要有一个停止标准
- 测试停止标准
- 测试阶段(进行到β测试后期的时候就可以准备停止测试了)
- 测试用例(用例全部通过的时候就可以准备停止测试了)
- 缺陷收敛趋势(缺陷收敛的速度很慢的时候就可以停止测试了)
- 缺陷修复率(缺陷修复率很高的时候就可以停止测试了)
- 覆盖率(覆盖率较高的时候就可以停止测试了)
- 缺陷度量(缺陷经过度量之后已经很小的时候就可以停止测试了)
- 质量成本(质量成本已经很高的时候就可以停止测试了)
认为当某一个时刻出现故障的概率足够小的时候就停止验收测试
如下图:
软件测试的组织
- 测试团队
- 开发团队
- 开发团队中配备测试人员
- 项目团队中若干测试团队
- 独立测试专家
- 单独测试部门
- 测试人员
- 测试经理
- 测试设计人员
- 测试自动化人员
- 测试管理员
- 测试人员
6.3 软件测试技术
软件测试技术相关概念
相关概念
- 软件测试的定义(软件测试策略的定义是什么?——为开发人员,质量保证组织以及客户提供路线图,规定了软件测试的步骤)
- 在某种指定的条件下对系统或组件操作,观察或记录结果,对系统或组件的某些方面进行评估的过程
- 分析软件各项目以检测现有的结果和应有结果之间的差异,并评估软件各项目的特征的过程
- 软件缺陷。下面给出几个软件缺陷的情况(前面四个都是跟产品说明书有关的)
- 软件未实现产品说明书要求的功能。
- 软件出现了产品说明书指明不能出现的错误。
- 软件实现了产品说明书未提到的功能。(这个要看实现的功能是有益的还是有害的,有害的才算是软件缺陷)
- 软件未实现产品说明书虽未明确提及但应该实现的目标。
- 软件难以理解、不易使用、运行缓慢
- 验证与确认(什么jb)
- 验证:对软件每一个开发过程的输出,都要检查是否正确完整地实现了规格说明
- 确认:对于每一个特定的测试级别,都要检查开发阶段的输出是否满足了具体的需求以及与这些特定级别相关的需求
- 软件质量保证:是指按照一定的开发标准、过程和步骤对软件产品质量进行评估的活动(就是最上面的概念)
- 软件测试与软件质量保证的不同:
- 软件测试:找出软件缺陷并确保修复(这个时候软件缺陷已经存在了)
- 软件质量保证:建立、执行改进过程并防止缺陷的标准和方法(是为了预防缺陷)
- 测试与调试
- 测试:目的是发现软件缺陷的存在
- 调试:目的是定位并修复软件缺陷
- 测试用例:测试用例是测试输入、执行条件和预期结果(所以写后面的用例的时候一定要加上预期结果。还可以在用例中加上实际结果)的集合。如下图:
目的与原则
- 软件测试的目的
- 确认系统满足其预期的使用和用户的需要。
- 确认解决了所需解决的问题
- 便于及早发现软件和系统的异常。
- 及早提供软件和系统的性能的评估。
- 为管理提供真实信息,以决定当前状态下发布产品在商业上的风险
- 软件测试的原则
- 穷尽测试是不可能的
- 测试无法显示潜伏的软件缺陷
- 测试活动应尽早进行
- 软件缺陷具有群聚性
- 注意“杀虫剂”现象
- 尽量由独立的测试团队进行测试
评估准则
- 覆盖率:100%的覆盖率不现实(就是软件测试原则中提到的,穷尽的软件测试是不可能的)
- 覆盖率的计算如下图:
- 故障插入:是一种统计方法,用于评估遗留在程序中的故障的数量和种类(什么标记重捕法)
- 方法:将故障插入到程序中,观察在测试中能否检测到该故障
- 变异分值:该指标与变异测试密切相关
- 变异测试:将一个程序变异为两个或多个程序,然后使用相同的测试用例执行测试,评估程序的变异能力
主要测试方法
- 白盒测试:考虑系统或组件的内部机制的测试形式(也就是:从程序本身结构出发的测试方法)
- 黑盒测试:忽略系统或组件的内部机制,仅关注于那些响应所选择的输入及相应执行条件的输出的测试形式(也就是:忽略程序本身的结构,只关注程序的输入输出的测试方法)
- 灰盒测试:介于白盒测试与黑盒测试之间的一种测试,多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况(也就是:既要关注程序本身的结构,也关注程序的输入输出的测试方法。至于为什么常用在集成测试是因为前一个测试阶段——单元测试采用白盒测试,后一个测试阶段——系统测试采用黑盒测试,集成测试作为过渡阶段就采用灰盒测试了)
白盒测试
白盒测试概念
- 把测试对象看做一个透明盒子,允许利用程序内部逻辑结构及有关信息,进行测试。(也就是白盒测试是从程序内部的逻辑结构出发的一种测试方法)
- 通过在不同点(就是在程序分支的地方)检查程序的状态,确定实际的状态是否与预期的状态一致(用例里面要体现预期结果)。
- 又称为结构测试(因为是基于程序内部结构的)或逻辑驱动测试(因为程序常常是在逻辑处出现不同点,也就是分支的)
- 白盒测试的检查范围
- 对程序模块的所有独立的执行路径至少测试一次(基本路径覆盖,在后面的白盒测试续中会进行介绍)
- 对所有的逻辑判定,取“真”与取“假”的两种情况都至少测试一次(分支覆盖)
- 在循环的边界和运行界限内执行循环体(有点像在白盒里的边界值分析,注意这里是对循环使用)
- 测试内部数据结构的有效性等
- 白盒测试——完全测试的困难性(还记得软件测试的原则不,穷尽的软件测试是不可能的):对于多条件分支的循环嵌套,路径(注意不是基本路径数量,因为基本路径覆盖要求了循环只执行一次)数量是指数级增长的
语句覆盖
- 逻辑覆盖(也是白盒测试被称为逻辑驱动测试的原因):是一种以程序内部逻辑结构为基础设计测试用例的技术(所以逻辑覆盖是白盒测试的一种技术,或者说方法)
- 语句覆盖的概念:就是设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次(所有语句都执行一次)
- 如:
其中L1就实现了语句覆盖(L1是一个流程图的路径,根据这个测试路径能设计出一个用例)
分支覆盖
- 分支覆盖:就是设计若干个测试用例,运行被测程序,使得程序中每个判断的取真分支和取假分支至少经历一次。分支覆盖又称为判定覆盖(也就是if的取真路径和取假路径都要走过)
- 如:
其中L1和L2就满足了分支覆盖(L1走了所有的取真分支,L2走了所有的取假分支);同样的L3和L4也实现了分支覆盖
条件覆盖
- 条件覆盖:设计若干个测试用例,运行被测程序,使得程序中每个判断的每个条件的可能取值(也就是取真和取假)至少执行一次(最终设计出来的测试用例跟分支覆盖应该是大差不差的,要求所有条件的真假都是要走遍的)
- 如:
可以参考上述的规范,先对每一个条件进行编号,然后再进行条件覆盖
上述跟据L3和L4设计出的三个用例就实现了对所有条件的覆盖(也就是实现了条件覆盖)(实际上还能再耍流氓一点,一个用例走所有的取真条件,另一个用例走所有的取假条件,这样也实现了条件覆盖)
条件组合覆盖
- 设计足够的测试用例,运行被测程序,使得每个判断的所有可能的条件取值组合至少执行一次(这个时候就没办法偷鸡了,只能枚举。如果在一个判断中如果有n个条件,那么就需要为这个判断设计2的n次方个用例)
- 如下:
可以发现并不需要将所有判断的所有条件集中在一起(这样的话就是真纯纯指数级增长了),而是只要保证每一个判断的所有条件组合都执行到即可(所以理论上条件组合覆盖用例数的最大值应该是最多条件的那个判断决定的)
控制流图覆盖测试
- 控制流图覆盖测试:是将代码转变为控制流图(CFG),基于其进行测试的技术
- 控制流图中的符号
- 结点:符号○ ,表示一个或多个无分支的PDL语句或源程序语句(尽量还是一个圈圈代表一个语句)
- 边:箭头,表示控制流的方向(也就是程序执行的方向)
- 汇聚节点:在选择或多分支结构中,分支的汇聚处应有一个汇聚结点(汇聚节点也可以是一条语句)
- 区域:边和结点圈定的区域。对区域计数时,图形外的区域也应记为一个区域(也就是离散数学中计算区域的方法)
- 控制流图示例如下:
- 单条件嵌套:如果判断中的条件表达式是由一个或多个逻辑运算符 (OR, AND, NAND, NOR) 连接的复合条件表达式,则需要改为一系列只有单个条件的嵌套的判断(也就是把多个条件的判断改成单条件判断的嵌套)
- 如下图:
这就是一个多条件的情况,一个判断中有a和b两个条件,绘制这一段程序的程序流图的时候需要将这个多条件判断改成单条件判断的嵌套,也就是右图(先判断a,再判断b。这样也是有合理性的,就可以表示短路运算的逻辑了)。在这里需要注意,逻辑流应该是一样的,即将多条件判断改成单条件判断嵌套的时候,程序表示的逻辑含义不能改变
- 节点覆盖(直观上理解就是覆盖控制流图中的所有节点):对图中的每个节点,至少要有一条测试路径访问该节点显然,节点覆盖=语句覆盖(因为节点就是一条语句或者多条没有分支的语句,所以节点覆盖就是语句覆盖)
- 边覆盖:对图中每一个可到达的长度小于(无边图)等于1 的路径,中至少存在一条测试路径覆盖(真是NM不讲人话,就是所有的边都需要被测试用例覆盖到)。显然,边覆盖包含节点覆盖(走过了所有的边就一定意味着走过了所有的节点),且边覆盖也可以实现分支覆盖(分支覆盖本质上就是要走遍每一个分支,也就是走过每一条边)
- 路径覆盖(最顶的来了):就是设计足够的测试用例,覆盖程序中所有可能的路径(这个路径的数量就是指数级增长的了,有分叉路径的数量就要往上乘)
- 路径覆盖如下(注意这里的控制流图没有把多条件改成单条件):
这里因为有两个分支,所以总共有2的2次方,即四条路径
- 基本路径覆盖(重点捏):将覆盖的路径数压缩到一定限度内(就是从所有的路径中选出来有代表性的那一类),程序中的循环体最多只执行一次(就是从路径中选出有代表性的路径,也就是基本路径,然后对这些路径进行覆盖即可)
- 基本路径覆盖的步骤
- 绘制程序流图
- 分析控制构造的环路复杂度(也就是用欧拉公式)
- 导出基本路径集合(实际上就是独立路径集合)
- 设计测试用例时需要保证程序的每一条可执行语句至少执行一次(也就是基本路径覆盖最少要是一个节点覆盖)
- 程序的环路复杂性(欧拉公式。这个值就刚刚好等于平面图区域的数量):程序路径集中的独立路径条数(这个时候如果把独立路径都求出来了应该就是一个边覆盖了),这是确保程序中每个可执行语句至少执行一次(也就是进行了一个节点覆盖)所必需的测试用例数目的上界(因为这样算出来的是独立路径的条数,而独立路径集是对控制流图进行边覆盖的,边覆盖又一定是节点覆盖,所以是上界)。(对公式的理解:本质上如果不算最外面的面的话,边数和面数的关系应该是边数=面数+1,因为一个面由两个独立路径组成,这个时候如果加上外面的面,那么就是边数=面数,也就是这个公式的来源)
- 独立路径:从控制流图来看,一条独立路径是至少包含有一条在其它独立路径中从未有过的边的路径(就是到了其他独立路径到不了的地方。这里就有点像边覆盖了)
- 确定线性独立路径的基本集合(应该就是上面说的基本路径集合吧)步骤(就当成深搜来做就好了):
- 从源节点(控制流图的入口点)开始,一直走到汇节点(控制流图的出口点)。该路径作为基线路径。
- 接下来,重新回溯基线路径,依次“翻转”在判断节点上原来选择的路径。即当遇到节点的出度大于等于2时,必须选择不同的边。
- 重复以上过程,直到得到的路径数目等于V(G)(所以得到的基本路径的条数一定是面数)
- 注意:这里将求基本路径的过程当成是一个深搜的过程(因为两者本质上都是自底向上回溯),一直进行深搜直至得到的基本路径条数为VG。所以说作业四应该是做错了,我做成了边覆盖,而不是基本路径覆盖(基本路径覆盖本质上要找到的路径数是一定有VG条的,除非出现了死代码导致用例无法设计出来)
- 导出测试用例:根据判断结点给出的条件,选择合适用例确保基本路径集的每一条路径的执行(可能因为死代码没办法执行到每一条基本路径)
- 测试结果比较:测试执行后,与预期结果进行比较。
- 注意事项:非孤立的独立路径可以是另一条路径测试的一部分
- 对程序控制流图覆盖的排序如下图(基本路径覆盖做到了边覆盖,并且由于采用不完全深搜的方法导致有的边会被覆盖多次,所以是大于边覆盖的;但是基本路径覆盖又是路径覆盖剪枝的结果,所以基本路径覆盖又小于路径覆盖):
黑盒测试
黑盒测试的概念
- 测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性(黑盒测试不考虑程序的逻辑结构)
- 只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明(黑盒测试只关注输入输出,也就是只依据需求规格说明书进行测试)
- 又叫做功能测试或数据驱动测试(因为黑盒测试只关注输入输出)
- 黑盒测试的检查范围(主要是检查功能了)
- 是否有不正确或遗漏了的功能?
- 在接口上,输入能否正确地接受? 能否输出正确的结果?
- 是否有数据结构错误或外部信息访问错误?是否有初始化或终止性错误?
- 性能上是否能够满足要求?
- 黑盒测试——完全测试的困难性(还是软件测试的原则:穷尽的软件测试是不可能的),如下图(也就是枚举所有的输入是不现实的):
等价类划分
- 等价类划分的思想:把所有可能的输入数据,即程序的输入域划分成若干部分,然后从每一部分中选取少数有代表性的数据做为测试用例(实际上就是对枚举情况的剪枝)
- 等价类划分的测试步骤
- 划分等价类
- 建立等价类表,列出所有划分出的等价类
- 为每一个等价类规定一个唯一编号;
- 设计一个新的测试用例,尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步,直到所有的有效等价类都被覆盖为止(也就是有效等价类同时测试)
- 设计一个新的测试用例,仅覆盖一个尚未被覆盖的无效等价类,重复这一步,直到所有的无效等价类都被覆盖为止(无效等价类隔离测试)
- 等价类:某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的(或者说输入同一个等价类中的数据,程序的输出是一样的)
- 有效等价类:对于程序的规格说明来说,是合理的,有意义的输入数据构成的集合
- 无效等价类:对于程序的规格说明来说,是不合理的,无意义的输入数据构成的集合
- 等价类划分的原则(注意每一个有效等价类和无效等价类都需要一个唯一的编号;有效无效等价类要进行统一的编号)
- 如果输入条件规定了取值范围,或值的个数(如要求2<=输入串的长度<=8),则可以确立一个有效等价类和两个无效等价类,如下图:
- 如果输入条件规定了输入值的集合,或者规定了“必须如何”的条件,这时可确立一个有效等价类和一个无效等价类(也就是确定一个符合条件的,一个不符合条件的),如下图(这个是针对输入数据的,而不是针对数据类型的。也就是说对数据格式的要求不需要从多个方面来违反。也可以发现,如果要对数据进行违反的话,只能违反数据的子集。如下图中的13位数字串,就只能分别从“13位”、“数字串”等子集来进行违反,所以这个时候就不需要从多个方面来进行违反了):
- 如果输入条件是一个布尔量,则可以确定一个有效等价类和一个无效等价类(注意这里实际上有可能布尔值的两个取值对程序而言都是合法的,但是还是将假值作为无效等价类。当然这里还需要考虑题目描述的侧重点,题目可能侧重于是真还是假,这个时候就要将真值作为有效等价类,将假值作为无效等价类;题目还可能侧重于是bool型还是非bool型,这个时候就要将bool型当成有效等价类,非bool型当成无效等价类),如下图:
- 如果规定了输入数据的一组值(也就是给出了具体的、可枚举的值),而且要对每个输入值分别进行处理。可为每一个输入值确立一个有效等价类,所有不允许的输入值集合为一个无效类,如下图:
- 如果规定了输入数据必须遵守的规则,则可以确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则),如下图(这个是针对数据类型的。也就是说数据类型要从多个方面来违反规则。也可以注意到这个时候违反规则是跟原规则是并列的,而不是上面数据的那种子集关系。如下图中的字符型,违反这个规则生成的无效等价类就是整数型、浮点型、bool型,这些都是跟字符型并列的):
- 下面给出一个等价类划分的例题:
注意到覆盖无效等价类的时候只需要写当前测试用例是覆盖了哪一个无效等价类即可(所以写这个的时候一定要按顺序,先写有效等价类,再写无效等价类)
边界值分析
- 边界值分析的含义:黑盒测试方法,对等价类划分方法的补充
- 边界值分析的意义:大量的错误是发生在输入或输出范围边界上,边界测试可以查出更多的错误
- 边界值分析的方法:确定边界情况选取正好等于,刚刚大于,或刚刚小于边界的值做为测试数据做为测试数据
- 边界指标:相对于输入、输出等价类而言,稍高、低于其边界值的一些特定情况(看不懂)
- 边界值分析——单侧边界
- 第一种是单侧边界为闭区间的情况:此时选择边界点、边界点加一个步长的点和边界点减一个步长设计测试用例(也就是闭区间选取三个点进行测试),如下图:
- 第二种是单侧边界为开区间的情况,选择边界点、边界点范围内方向移动一个步长的点计测试用例(也就是开区间选取两个点进行测试,并且两个点的预期结果应该是不一样的,也就是一个是边界点,而另一个点是边界内的点而不是边界外的点的原因,因为如果此时选取的是边界外的点的话,选取的两个点就属于同一个等价类,就没有意义了),如下图:
- 下面给出一个单侧边界的边界值分析的例题:
- 边界值分析——区间范围
- 上点,即边界点(就是取到边界值的点),不管是开区间还是闭区间。
- 内点,上点范围内的任意一点(就是边界范围内,或者说区间内的点)
- 离点,离上点最近的点称为离点。开区间为上点范围内加一个步长,闭区间为上点范围外加一个步长(实际上也是为了保证离点和上点不属于同一个等价类)
- 区间为闭区间的情况:闭区间中的情况,上点为可以取值的点,在上点之间任取一点就是内点。而紧邻上点范围之外第一对点为离点(目的是为了保证离点和上点不属于同一个等价类)。闭区间边界值分析如下:
- 区间为开区间的情况:开区间:开区间中,上点与内点的定义仍然不变。而离点就是上点内部范围内紧邻上点的一对点(目的也是为了保证离点和上点不属于同一个等价类)。开区间边界值分析如下:
- 区间为半开半闭区间:本质上就是结合了闭区间和开区间,只要保证上点和离点不属于同一个等价类即可。半开半闭区间举例如下:
- 边界值分析——多元函数
- 这里以二元函数为例
- 按照一元函数的方法对每一个变量选择上点、内点和离点,然后用第一个变量的上点、离点与第二个变量的内点配对设计4个测试用例,再用第一个变量的内点与第二个变量的上点、离点配对设计4个测试用例,最后两个变量的内点配对形成最后一个测试用例,共设计9个测试用例。
- 总结:就是每次只有一个变量是取上点和离点,其他的变量都取内点,直至所有变量的上点和离点都被取过,最后再将所有变量的内点组合成一个测试用例(对于任意元的函数都是这样的)。如下图:
下面给出一个等价类划分和边界值分析的例题,用于明确步骤如何书写:
可以注意到这里是先将等价类划分做完,然后再进行边界值分析,然后再将用例合并(主要是内点和有效等价类的合并),最后再画出等价类划分和边界值分析的测试用例总表(这里可以看见等价类划分在左边,边界值分析在右边,实际上分成两张表就好了)
状态测试
- 软件状态:软件当前所处的条件或者模式
- 状态测试:在黑盒测试阶段,通过对状态(这个感觉有点面向过程了昂)的测试间接地加以验证功能
- 状态测试的步骤
- 建立状态转换图(byd自动机还在追杀我)
- 找出从一种状态转入另一种状态所需的输入和条件(状态转换条件)
- 标识出软件可能进入的每一种独立状态(确定状态集)
- 找出进入或退出某种状态时的设置条件及输出结果(状态转移结果)
- 这里就摆一张状态转换图在这(状态转换图应该不考吧,因为感觉是面向过程的了):
- 根据状态转换图设计测试用例
- 每种状态至少访问一次(就相当于进行了白盒测试中的节点覆盖,只不过这个时候图上的每一个节点都是一个软件状态,而不是代表程序的结构,所以是黑盒测试)
- 测试看起来是最常见和最普遍的状态转换
- 测试状态之间最不常用的分支
- 测试所有错误状态及其返回值
- 测试状态的随机转换
静态分析方法
- 静态分析方法的含义:不运行程序,通过检查和阅读等手段来发现错误并评估代码质量的测试技术(并不是在源代码编写完成之后进行的,而是在源代码编写过程中进行的)
- 静态分析方法的作用
- 规范代码标准,进行质量监控,提高可靠性
- 尽早通过源代码检查发现缺陷代码
- 审核定位易产生错误的模块
- 静态分析方法的适用范围:静态分析方法是一种非常有效的质量保证手段,越来越多地被采用
- 静态分析方法的内容:需求、设计、代码
- 静态分析方法的类型
- 同事审查:适用于初次审查,是要求最低的正式方法,通常称为伙伴审查
- 走查:在开发组内部进行
- 审查:以会议形式,由开发组、测试组以及相关人员联合进行
- 作者:Noah
- 链接:https://imnoah.top/article/SoftwareEn/Chapter6
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。