软件测试
简介
软件测试是通过考虑软件的所有属性(可靠性,可伸缩性,可移植性,可重用性,可用性)和评估软件组件的执行来查找软件错误或缺陷来识别软件正确性的过程。
- 软件测试提供了软件的独立视图和目标,并确保软件的适用性。它涉及在所需服务下测试所有组件,以确认它是否满足指定的要求。该过程还向客户提供有关软件质量的信息。
- 测试是强制性的,因为如果软件由于缺乏测试而导致任何时间失败将是一种危险的情况。因此,没有测试软件就无法部署到最终用户。
- 测试是一组用于在预定义脚本下确定应用程序正确性的技术,但是,测试无法找到应用程序的所有缺陷。测试的主要目的是检测应用程序的故障,以便发现和纠正 故障。它并未证明产品在所有条件下都能正常运行,但仅表明它在某些特定条件下无法正常工作。
- 测试提供了比较软件的行为和状态与机制的比较,因为该机制可以识别问题。该机制可以包括相同指定产品的过去版本,可比较产品,以及预期目的,相关标准或其他标准的界面,但不限于这些。
- 测试包括检查代码以及各种环境中的代码执行,条件以及代码的所有检查方面。在当前的软件开发方案中,测试团队可能与开发团队分开,以便从测试中获得的信息可用于纠正软件开发过程。
软件测试的基本过程:分析测试需求、编写测试计划、设计与编写测试用例、执行测试、评估与总结。
软件测试的目的/目标:
功能测试
软件测试启动与研读需求文档
测试工作人员
测试工作人员组成:业务分析人员、测试经理和组长、测试分析设计人员、测试执行人员、 自动化测试人员、系统工程师/技术支持
软件质量需求
分类
- 软件质量需求用于确定测试目标
- 测试目标包括:功能、性能、界面、易用性、兼容性、安全性、可用性、可维护性、可扩展性等。
- 功能以外统称为非功能性。
功能
- 软件能做什么
- 需要做什么
- 怎么做才是正确的
- 哪些功能要测试、哪些功能不需要测试
- 哪些功能先实现或先测试
性能
- 反映软件运行时的效率和占用资源情况的能力。 - 时间特性:时间短、速度快、效率高- 资源特性:占用资源(CPU、内存、硬盘、网络)少。
界面(UI)
- 布局合理;
- 控件位置恰当;
- 文字没有乱码、字体大小合适;
- 颜色使用恰当;
- 图片、表格恰当、舒适、美观;
易用性
- 在指定条件下使用时,软件产品被理解、学习、使用和吸引用户的能力
兼容性/可移植性
- 指软件产品从一种环境迁移到另一个环境的能力,反映一个软件与不同的硬件环境、操作平台、其他软件的共同使用的能力。、 - 包括与不同硬件、平台、软件自身不同版本、其他软件、数据和兼容。
安全性
- 指软件产品保护信息和数据的能力。
可用性/可靠性
- 指系统正常运行的能力或程度,可用性=正常运行时间/(正常+不正常时间) * 100% - 可用性指标一般要求达到4个9即99.99%。(全年52分钟不正常工作)或5个9即99.999%(全年5分钟),对一些军事系统,可用性高达7个9(99.99999%,全年不超过两秒钟)。- 一般测试时间不足,可以采用空间换时间的办法,在高负载情况下进行为期一周或一个月的测试。- 关注MTTF(平均无故障时间)、MTTP(平均恢复时间)、MTBF(平均失效间隔时间)。
可维护性
- 指软件产品可被修改的能力。 - 修改可能包括修正、改进或软件对环境需求和功能规格说明变化的适应。- 可维护性的软件应该是易改变的、稳定的、易测试的。
可扩展性
- 通过很少的改动就能实现整个系统处理能力的增长
研读需求文档
测试需求分析的过程
- 收集与研读文档,提出并解决问题,整理需求信息
- 功能拆分、功能描述、需求整理
- 编写测试点
- 需求评审
研读文档主要内容
- 提取有用的需求信息
- 提出需求中不清晰、不理解、不明白的问题 - 和用户、业务人员、产品经理或产品设计人员、开发人员等沟通
怎么研读文档
- 总体上: - 分析软件的用户群,分析用户的实际需要。- 分析软件的开发环境、开发语言。- 分析软件架构、软件的运行环境和平台、数据库类型。- 分析软件要实现哪些目标以及具体的要求是什么。- 分析软件有哪些功能,每种功能要完成什么业务,业务实现、业务逻辑、业务流程- 分析哪些功能更关键- 明确测试周期,测试目标,测试范围
- 细节上: - 分析每个模块或功能上的实现的功能- 设计的开发原理包括数据类型- 从用户使用场景角度分析业务流程- 记录业务规则
- 实施 - 以情景再现的形式写出需求信息
软件测试的原则
所有测试都应追溯到用户需求
- 缺陷的源头:软件缺陷出现最多的地方是软件需求规格说明书,而不是程序代码。
- 测试的第一个任务是需求分析;
- 制作缺陷的罪魁祸首不是程序员
- 做好需求评审
尽早启动测试工作
- 缺陷雪崩:
- 测试的成本:
- 测试应该是与软件开发或维护工作并行进行的一个过程。
早做测试计划
- 软件测试不仅仅是测试执行
- 应该在测试工作真正开始之前的较长时间内就进行测试计划
穷尽测试不可能&软件测试有风险
- 完全测试、完美测试、充分测试不可能。
- 测试数据输入量太大、时间不够等
- 使用风险分析,确定测试的重点和优先级,控制测试的开销(时间、成本、资源)。
测试工作的Good-enough原则
- 既不要做过多的测试,也不做不充分的测试。
- 指定最低测试标准和测试内容,然后具体问题具体分析
Pareto帕累托法则(28法则)应用于软件测试
- 一般情况下80%的缺陷聚集在20%的关键核心业务模块中
- 做好测试需求分析和测试计划,分清测试重点
- 尽早测试
- 持续测试
尽可能使用分阶段测试
- 单元测试->集成测试->系统测试->验收测试
应该由独立的第三方来构造测试
- 为了达到最佳效果,最大可能的发现错误的测试
测试旨在发现存在的缺陷
- 软件测试可以报告软件缺陷存在,不能报告软件缺陷不存在
- 即使在测试过程中未发现软件的失效,也不能证明被测软件没有错误。
为了保证测试的有效性和高效性,测试必须是破坏性、系统化的
- 充分、有效、系统的测试可以减少软件中未被发现缺陷的可能性
找到的软件缺陷越多,说明软件隐含的缺陷越多
- 缺陷具有群集效应 - 应该在发现缺陷的地方继续找找
杀虫剂怪事
- 软件测试越多,其对测试免疫力越强 - 程序员对测试人员的惯用伎俩已经可以主动躲避了
- 测试人员必须不断编写不同的、新的测试程序
并非所有的软件缺陷都要修复
- 没有足够的时间
- 不算真正的软件缺陷
- 修复的风险太大
- 不值得修复
使用木桶原理
- 在软件产品生产方面就是全面质量管理(QTM)的概念
- 团队合作
前进两步,后退一步
- 测试中的一个基本问题是–缺陷修复总会以(20%-50%)的几率引入新的缺陷。
- 每次修复之后,必须做确认测试和回归测试 - 再测试/确认测试,重新测试;1.看老问题还存在吗;2.看有无新问题
软件测试是一个迭代的过程
- 无论项目采用何种开发模型,测试人员总是一个一个版本地测试,其测试活动总是迭代向前的
测试要遵循标准
- 标准的分类:国际标准:如ISO、CMM、IEEE;国家标准:GB、GB/T;行业标准;公司标准;用户规定
软件测试工程师的要求
- 测试需要懂行业知识-态度
- 三心二意、懂开发、善于思考-品质
- 处理好与其他小组的关系-品质
软件开发和测试模型
软件开发模型
为什么学习软件开发模型
了解开发能够更好的有针对性的做好测试
什么是软件开发模型
软件开发生命周期模型是软件产品从最初构思到退役的过程
常见的开发模型
- 大爆炸模型- 直接冲过河的模型:一大堆东西(人力和资金)放在一起,巨大的能量释放 ,要么产生优秀的产品,要么是一堆废品。- 特点:是最简单的软件开发模式,计划、进度安排和正规开发过程都几乎没有,所有精力都放在开发软件和编写代码上;- 一般,大爆炸模式几乎没有测试,即使有也要挤在产品发布前,通常都会避免在此模式下进行测试。
- 边写边改模型- 摸着石头过河的模型- 默认的开发模式- 在大爆炸基础上更进一步,至少考虑了产品需求- 最初只有粗略的想法,接着进行一些简单的设计,然后开始漫长的来回编写、测试和修改缺陷的过程,知道觉得足够才发布产品,是测试期间最有可能碰到的模型- 没有计划和编写文档,项目能够迅速展示成果,比较适合用完就扔的项目- 软件测试会陷入无休止的循环往复,直到软件发布
- 瀑布模型- 制定周密计划的模型- 如果项目未准备好进入下一步,就停滞下来直到准备好- 所有的一切都有完整细致的说明,得以制定精确的测试计划- 测试对象非常明确,即程序- 测试被认为是在软件开发过程中的后期阶段进行的一次性活动,这带来了一个巨大的缺点,因为测试尽在最后进行,而一些根本性问题可能出现在早期,但是直到准备发布产品时才可能发现
- 螺旋模型- 计划赶得上变化的模型- 开始不必定义所有的细节,从小开始,定义重要功能,努力实现这些功能,接收客户反馈,然后进行下一阶段,重复上述过程,直到得到最终产品- 特别适合大型复杂系统- 包含一点瀑布模式(分析、设计、开发和测试的步骤)、一点边改边写模式(螺旋模式的每一次)和一点大爆炸模型(从外界观察)。- 测试人员喜欢该模型。测试一直在进行
- 敏捷开发模型- 另一些名称:快速原型、极限编程或进化开发等- 核心思想:以人为本,适应变化- 提倡迭代式和增量式的开发模式,强调测试在其中的重要作用- 以用户为中心、以客户需求为导向的开发过程,随时做好迎接变化的准备,客户是敏捷的关键环节- 没有单一固定的开发方法或过程,共同点:依赖客户的参与、测试驱动以及紧凑的迭代开发周期
软件测试模型 - 指导测试过程
常见的测试模型
- V模型
- V的左端表示传统的瀑布开发模型,而V的右端表明相应的测试阶段
- 测试分为不同的级别或阶段
- 每个阶段都与开发的各阶段相对应
- V模型的测试策略包括底层测试和高层测试,低层测试是为了源代码的正确性,高层是为了整个系统满足用户的需求
- 测试是开发之后的一个阶段,太晚了
- 测试的对象就是程序本身,忽视了对文档和数据的测试
- 没有循环进行测试
- W模型- 基于尽早和不断测试的原则, 既强调测试方案设计,也强调测试执行。- 开发与测试同步,做到了尽早测试,有利于尽早地全面的发现问题- 测试对象不仅仅是程序,需求和设计也进行了测试- 测试是线性关系,没有进行循环测试,不能迭代式测试
- H模型
- 将测试活动完全独立出来,形成一个完全独立的流程,将测试准备活动和测试执行活动清晰地体现出来。测试贯穿产品整个生命周期,与其他流程并发地进行—>、(伴随第三方测试)
- 当个测试时间点就绪时,软件测试即从测试准备阶段进入到测试执行阶段
- 测试尽早准备,尽早执行
- 软件测试是根据被测物的不同而分层次进行的。不同层次的测试活动可以是按照某个次序先后进行的
- X模型
- 前置模型
- 敏捷测试模型
- 为了满足极限编程XP的流程和思想,开发人员使用了极限测试方法,该方法强调连续测试
- 测试在XP的地位非常重要,首先创建单元测试和验收测试,然后才能创建代码库。这种形式的测试被称为极限测试XT。
- XP模型需要客户参与,高度依赖模块的单元和验收测试
- 敏捷是协同测试的一种形式,程序员结对编程,是连续测试
- 敏捷测试侧重单元测试和验收测试
测试需求分析与测试用例分析
文本框控件知识
- 文本框和密码框: - 长度要求和输入内容限制- 长度要求、不允许明文显示、禁止复制粘贴、输入内容限制、两次密码要一致
- 单选按钮、组合列表框/下拉框、数码框- 标题/提示文本不缺失且正确;各个选项正确;;只能选中一个;要有默认选项;一般不能取消选中;存入后台的数据正确。- 通常单选,条目内容正确;横向显示要完整;条目功能要正确实现;组合列表框可能允许输入数据。- 能使用上下箭头控制数字变动;数字有范围限制;能使用上下箭头控制数字自动循环或者到达边界时停止;可以直接输入数字
- 复选框- 选项正确;可以不选、随便选;可以取消选中;每个复选框功能都正确实现
- 列表框- 通常多选;条目内容要正确;横向和纵向显示完整;条目功能要正确实现
- 命令按钮- 实现所需的功能; 出现错误时,给出明确的提示信息。
- 其他界面元素- 窗口标题:不缺失、显示正确。- 选项卡:CTRL+tab切换- 默认焦点(初始时光标所在位置)- Tab顺序- 快捷键/热键:第一次按alt,往后不需要按
大纲法分解功能(功能分解)
大纲法主要用于对软件进行功能拆分
- 模块:包括多个功能操作的对象或功能集合,如文件(菜单)等。
- 功能点/功能:能独立完成一件事或者一个业务。如新建、打开等。
- 业务流程:软件为了完成业务或完成核心功能所经历的步骤。
- 业务逻辑:是对业务的不同处理方式
- 业务规则:如要求用户只能用中文,5-11个字符等。
编写测试需求分析说明书
将功能拆分与整理的需求信息写入测试需求分析 ,这就是测试需求分析说明书
例子:需求编号、功能、一级功能、二级功能、原始需求、需求整理
测试需求分析与测试用例设计方法
场景法
- 测试点/检查点:测试时应该考虑可以测试的诸多方面
- 概述:模拟用户操作软件时的情景,主要用于测试系统的业务流程;如先关注主要功能和业务流程是否正确实现,这就需要使用场景法
- 场景用来描述软件操作的路径:基本流(正确的操作流程)和备选流(模拟错误的操作流程)
- 步骤:分析软件需求;从用户使用情景角度,写出业务流程和业务规则;写出基本流场景和备选流场景
等价类划分法
等效分区是一种软件测试技术,其中输入数据被划分为有效值和无效值的分区,并且所有分区必须表现出相同的行为。如果一个分区的条件为真,则另一个等效分区的条件也必须为真,如果一个分区的条件为假,则另一个等效分区的条件也必须为假。
- 等价划分的原则是,测试用例应设计为至少覆盖每个分区一次。每个等效分区的每个值必须表现出与其他分区相同的行为。
- 等效分区源自软件的要求和规范。这种方法的优点是,它有助于减少测试时间,因为从无限到有限的测试用例数量较少。它适用于测试过程的各个层面。
- 通过需求分析,找出程序的输入域;将输入域分成若干类;每一类中选取代表性数据等价这一类中的其他值。
- 步骤:需求分析;划分等价类(根据需求,有效等价类、无效等价类)并细化(根据计算机知识)
- 注意事项: - 有效和无效要同时考虑- 等价类划分不要过错或过细- 仔细划分,审查划分
边界值分析法
边界值分析是广泛使用的黑盒测试用例设计技术之一。它用于测试边界值,因为边界附近的输入值具有较高的误差机会。
每当我们通过边界值分析进行测试时,测试人员会在输入边界值时关注软件是否产生正确的输出。
边界值是包含变量上限和下限的值。假设age是任何函数的变量,其最小值为18,最大值为30,18和30都将被视为边界值。
边界值分析的基本假设是,使用边界值创建的测试用例最有可能导致错误。
18和30是边界值,所以测试人员更关注这些值,但这并不说就忽略了像19,20,21,27,29这样的中间值。为该范围的每个值开发测试用例。
边界值的测试是通过制作有效和无效的分区来完成的。测试无效分区是因为在不利条件下测试输出也是必要的。
- 步骤:分析需求,找出边界;写出边界值:最小值、小于最小值、最大值、大于最大值;
决策表法
决策表技术是一种系统方法,它以表格形式捕获各种输入组合及其各自的系统行为。
它也称为因果表。该技术用于系统地选择测试用例; 它节省了测试时间,并为软件应用程序的测试区域提供了良好的覆盖。
- 决策表技术适用于在两个和两个以上输入之间具有逻辑关系的函数。
- 该技术与输入的正确组合有关,并确定各种输入组合的结果。要通过决策表技术设计测试用例,需要将条件视为输入,将操作视为输出。
- 步骤:需求分析:分析输入和输出:用等价类划分分析输入和输出的各种情况;画判定表;分析与简化判定表
- 局限性:可能会导致测试量爆炸
- 优化策略:测试基本功能的保留;一个输入错误,另外输入无所谓,可以整合;所有的输入都要错误过
错误推测法
- 根据经验或直觉推测程序中可能存在的各种错误,从而有针对的编写测试用例
- 错误推测分类:输入数据测试方面、输出数据测试方面、数据结构测试方面、文件系统方面
输入数据测试方面:
- 输入非法数据:输入非法类型、范围/长度、格式;(注意:一般用于键盘输入数据;错误信息和错误要一致,错误信息不能为空,不能只是错误代码,不能包含开发信息)
- 输入默认值:接受默认值、键入空值、将默认值改为另一个值、将默认值改为另一个值再改为空值(注意:适用于有默认值的地方)
- 输入特殊字符集:根据行业知识,具体问题具体分析,列出分析表格(注意:适用于不能输入特殊含义的地方)
- 输入合法数据的非法组合:输入可能是出现问题的组合值(注意:适用于输入值之间存在依赖关系时)
- 通过复制粘贴强制输入程序不允许输入的数据
输出数据测试方面
- 同一个输入产生多种输出:详细测试每一种输出,不要有遗漏
- 验证输出结果的正确性:不仅测试输入的正确性,还要检查结果的正确性
数据结构方面的错误推测
- 数据结构溢出 :变量:上溢-值太大、下溢-值太小;数组:上溢-数据量太多、下溢-数据量太小(适用于程序中存在变量、数组等数据结构时)
- 计算结果溢出:输入非法值、很大或很小的数据,强制结果产生上溢或下溢
- 操作符与操作数不符:找到程序中容易引起操作数和操作符不符的计算、表达式等(适用于需要进行数值计算程序和图形操作程序的测试时,如加减乘除等)
文件系统方面
- 使文件系统超载:创建满容量或近乎满容量的文件系统,然后强制执行各种输入输出访问文件系统的操作;打开足够多的文件,文件打开时会强制创建备份副本,从而占用双倍的存储空间;使用工具Canned Heat模拟文件系统超载(适用于数据存储到硬盘中时)
- 更改文件访问权限:1.不同的用户对相同的文件具有不同的访问权限,需要考虑登录同一个机器的多个用户操作相同文件的权限问题–>打开文件,在操作系统中修改访问权限;2.两个应用程序打开,关闭同一个文件–>相同应用的不同版本、一个应用打开另一个应用已打开的文件,看冲突情况(适用于对文件进行读写的应用程序)
- 使介质忙或不可用:使用一些测试工具来模拟磁盘的状态(适用于应用程序的运行需要消耗大量内存或运行时需要其他)
- 介质损坏:使用实际损坏了的介质,检查应用程序对错误的处理能力;也可以使用软件进行模拟(损坏的介质可能使操作系统传回错误代码,是否使用此方法主要考虑数据对用户的重要性)
编写测试点,可以使用XMind进行功能拆分
将测试点写入测试需求分析说明书,或者使用XMind等,留存下来以供将来编写测试用例
需求评审
意义:
- 对软件需求进行正确性的检查
- 保证软件需求的可测实性
- 与相关人员进行沟通,避免在后期产生不同的理解
- 更好地理解产品的功能性和非功能性需求
- 测试的目标和范围确定,降低测试的风险
质量要求:
- 正确性
- 完备性
- 易理解性
- 一致性
- 可行性
- 已修改性
- 可测实性
- 可追溯性
参加人员:
- 用户代表*
- 需求人员
- 产品经理
- 项目经理
- 开发人员*
- 开发经理
- 测试人员*
- 测试经理
- 市场经理
- 质量保障人员
注意事项:
- 明确自己的角色和责任
- 熟悉评审内容
- 针对问题阐述观点,而不是针对个人
- 分别讨论主要的问题和次要的问题
- 采取适当的、灵活的表述方式
- 对发现的问题跟踪下去
- 在需求形成的过程中,进行分阶段的多次评审
软件测试阶段
软件测试分类
- 测试阶段也叫做测试级别
- 分类: - 单元测试- 集成测试- 系统测试- 验收测试
组件测试/单元测试
组件
- 组件也称为单元。
- 组件时软件里最小的、可以单独执行编码的单位,通常由一个人完成编程
- 对于采用流程语言设计的软件,单元可以由一个或若干个最接近的函数或过程所组成
- 对于面向对象的,单元可以是一个类或类的实例,或者由方法实现的功能
- 对于网页或用户窗口界面,单元可以是一个文字输入窗口或一个按钮等
含义
重点、所需知识和前提条件
单元测试使用的技术、能够发现的缺陷
黑盒测试只关心功能的正确性,输入和输出正常就可以;白盒测试关注程序里的处理流程和程序结构;灰盒测试,白盒测试和黑盒测试相结合的技术。一般来说,是先测黑盒,再测白盒。
组件测试需要编码
驱动器
是通过接口与测试对象通讯的辅助工具。用于调用被测试的组件或系统替代性程序。
桩模块(Stub)
桩用于替代或模拟那些还没有完成的组件(模块),用于模拟输入和输出(针对不完整的功能)
模拟器(Simulaition)
用一个系统来描述另一个要测试的抽象系统的行为特征。
集成测试
含义
单元测试通常是单人执行,而集成测试通常是多人执行或第三方执行。
集成测试的重点、所需知识和前提条件
集成测试使用的技术、能够发现的缺陷
集成测试的策略
- 自顶向下集成
- 自底向上集成
系统测试
含义
系统测试的重点、所需知识和前提条件
系统测试使用的技术、能够发现的缺陷
验收测试
含义
验收测试的分类
alpha测试(内测):
- alpha测试的目标是通过识别和修复以前测试过程中无法发现的错误来纠正软件产品。它是在开发结束时和软件beta测试之前完成的。
- 软件工程师或质量保证人员执行alpha测试。通常,它有两个阶段,在第一阶段,开发人员使用调试器软件或硬件辅助调试器,这有助于非常快速地捕获错误。在alpha测试期间,存在大量错误,缺少功能和崩溃。在第二阶段,质量保证人员通过涉及黑白盒和白盒测试技术进行alpha测试。这是一个额外的测试环境。
- Alpha测试在单独的计算机系统上的实验室测试环境中完成。由项目经理和开发人员组成的小组定义了alpha测试的目标,并整合了不断发展的项目的结果。 测试组的一些基本步骤如下: - 检查软件的功能要求和设计规范。- 根据功能开发测试用例。- 执行所有测试用例。- 发现缺陷。- 修复缺陷。
Beta测试(公测):
- Beta测试是验收测试的一部分,旨在通过最终用户验证产品的可用性,功能,可靠性和兼容性。当用户通过提供实际输入值来验证软件时,它会为软件增加价值。
- 软件的用户通过向所有可执行功能提供实时输入值来执行beta测试。只有用户才能在所需的质量方面对应用程序进行认证。用户视图被视为测试结果,这些也有助于提高性能和提高质量。
- Beta测试生命周期从Plan开始,到用作beta测试软件的产品发布时结束。设计,构建,测试,审查也是beta测试生命周期的一部分。
测试计划
测试计划的定义
- IEEE 829-1983测试计划的定义与目的- 一个叙述了预定的测试活动的范围、途径、资源及进度安排的文档。它确认了 测试项、被测特征、测试任务、人员安排以及任何偶发事件的风险。- 软件测试计划是指导测试过程的纲领性文档。计划可以统一认识,可以规划过程。- 测试计划包含了产品概述、测试区域/测试范围(测试项)、 测试目标(被测特征)、测试优先级、测试配置/测试资源(硬件、软件、人力、技术等)、测试周期、进度安排(测试任务、人员安排)、 测试策略、测试方法/途径、测试交流、风险分析、测试标准、需交付文档等内容。
- 测试计划进入准则、退出准则与责任人-
测试计划编写原则
为了做好软件测试计划,需要注意以下几个方面:
- 明确测试的目标,增强测试计划的实用性。
- 坚持“5W+1H”规则,明确内容与过程。 - What(做什么)- Why(为什么做)- When(何时做测试)- Where(在哪里–测试环境)- How(如何做)- Who(谁来做)
- 采用评审和更新机制,保证测试计划满足实践需求 测试计划创建完毕后必须提交给由项目经理、开发经理、测试经理、市场 经理等组成的评审委员会审阅。
- 测试计划中不要包含详细的测试技术指标、测试步骤和测试用例。 - 测试计划和测试详细规格、测试用例之间是战略和战术的关系。
测试计划的主要工作(重点)
- 确定测试资源
- 工作量估算、里程碑和进度安排
- 风险分析
- 制定测试策略
- 编写计划书
确定测试资源
测试资源的分类
测试资源的规划
- 软件测试项目所需的人员和要求在各个阶段是不同的。
- 在初期,测试组长首先要介入进去,参与需求评审、确定测试需求和测试范围、 制定测试策略和测试计划等。
- 在测试前期,需要一些比较资深的测试设计人员、测试脚本或测试工具开发人员参与或负责软件测试需求的制定和分解、设计测试用例、开发测试脚本等工作。
- 在测试中期,主要是测试的执行,测试人员的数量取决于测试自动化实现的程 度。如果测试自动化程度高,人力的投入则不需要明显的增加:如果测试自动化程度低,对执行测试的人员要求就比较多了。
- 在测试后期,资深的测试人员可以抽出部分时间去做新项目的准备工作。
工作量估算、里程碑和进度安排
测试工作量估计(难点)
- 怎么确定测试工作量
- 测试的工作量是根据测试范围、测试任务和开发阶段来确定的。 - 团队工作效率越低,测试工作量越大。- 测试的质量要求越高,测试的工作量越大。- 不同的开发阶段的测试工作量的差异也较大。新产品第一个版本的测试的工作量要大一些,若后续版本功能增加加多,则后续版本测试量变大。- 编程质量越低,测试的工作量越大。- 程序复杂度越高,测试的工作量越大。- 之前测试的缺陷多且分布很广,测试工作量大。- 风险越多,等级越高,测试工作量越大。- 自动化程度越低,测试工作量越高。但是在很多情况下,测试自动化并不能大幅度降低工作量,因为测试脚本开发的工作量很大。
- 任务细分
- 工作分解结构表方法- 列出本项目需要完成的各项任务。- 对每个任务进一步细分,可进行多层次细分,直到不能细分为止。- 根据任务的层次给任务进行编号。
案例:
3. 测试工作量估算
案例:
- 考虑回归测试(如 2-3 轮) W= Wo + WoRl + WoR2 + Wo*R3 - W 为总工作量,Wo 为一轮测试的工作量,R为回归系数/风险系数。- 在代码质量相对较低的情况下,假定 Rl、R2、R3 的值分别为 80%、 60%、40%,若一轮功能测试的工作量是 100 个人日,则总的测试工 作量为 280 个人日。- 如果代码质量高,一般只需要进行两轮的回归测试,Rl、R2 值也降 为 60%、30%,则总的测试工作量为 190 个人日,工作量减少了 32% 以上。
测试里程碑和进度安排
- 里程碑 一般一个里程碑标志着上一个阶段结束、下一个阶段开始,也就是定义当前阶段完成的标准(Entry Criteria)和下一个新阶段启动的条件或前提(Entry Criteria)。
- 里程碑的特点
- 里程碑具有很强的时序性,可以有层次(分为父里程碑、子里程碑等)。
- 不同类型的项目,里程碑可能不同。
- 不同规模项目的里程碑,其数量的多少不一样,里程碑可以合并或分解。
- 软件测试中常见的里程碑 测试计划签发、测试用例签发、自动测试脚本完成、功能测试完成、性能测试完成 等。
- 进度安排进度安排就是确定里程碑的起止点。 案例:
测试风险分析与管理
对软件测试中的风险进行管理,基本内容有:风险识别、风险评估和风险控制。
风险识别
- 建立风险项目检查表,将测试范围、测试过程中的风险识别出来,按风险内容进行 逐项检查、逐个确认,确定哪些是可避免的风险,哪些是不可避免的,对可避免的 风险要尽量采取措施去避免。
风险评估
从成本、进度及性能三个方面对风险进行评估,通过评估可以确定这些风险的特点或可 能带来的危害,根据风险发生的概率和带来的影响确定风险的优先级。
风险控制
- 制定风险管理计划和风险应急处理方案,来降低风险和消除风险。
- 对风险的处理还要制定一些应急的、有效的处理方案。
- 做计划时,估算资源、时间、预算等要留有余地,不要用到 100%。
- 制定文档标准,并建立一种机制,保证文档及时产生。对所有工作多进行互相审查, 及时发现问题。
制定测试策略
什么是测试策略
- 描述当前测试项目的目标和所采用的测试方法;
- 描述在规定的时间内哪些测试内容要完成,软件产品的特性或质量在哪些方面得到 确认;
- 描述测试不同阶段(单元测试、集成测试、系统测试)的测试对象、范围和方法;
- 描述每个阶段内所要进行的测试类型(功能测试、性能测试、压力测试等)。
案例:分阶段的测试策略
- 严格执行代码复查,保证在早期就发现问题,而非在代码发布之后。
- 利用单元测试和集成测试,尽早地发现更多的问题,并准备好自动化测试的 BVT (Build Verification Test,软件包验证测试)。 - BVT 是开发人员检入自己的代码,项目组编译生成当天的版本后进行的 测试,主要目的是验证最新的软件版本在功能上是否完整,主要的软件特 性是否正确实现。冒烟测试通过后,就可以进行更大规模的测试了。- BVT 优点是时间短,缺点是覆盖率很低。BVT 测试也称“冒烟测试”。
- 不能忽略安全性测试、可用性测试、配置测试和数据完整性测试。
- 在功能性测试、安全性测试、配置测试中可进行一些探索性测试。
- 制定更为详细的 UAT(用户验收测试)测试计划,将其与测试脚本和培训材 料一起提供给用户,以帮助用户快速提高并完成任务。
编写测试计划书
- 测试计划是一个过程,不仅仅是“测试计划书”这样一个文档,测试计划会随着情 况变化不断进行调整,以便于优化资源和进度安排,减少风险,提高测试效率,并 及时修改“测试计划书”。
- 测试计划书的内容也可以按集成测试、系统测试、验收测试等阶段去组织。 为每一个阶段制定一个计划书,还可以为每个测试任务,目的(安全性测试、性能 测试、可靠性测试等)制定特别的计划书。
- 对于一些重要的项目,会形成一系列的计划书,如测试范围,风险分析报告、测试标准工作计划、资源和培训计划、风险管理计划、测试实施计划、质量保证计划等。
编写测试用例
测试用例的定义和内容
定义
- 对一项特定的软件产品进行测试任务的描述,指定输入,预期结果和一组测试项的 执行条件的文档。 - 体现测试方案、方法、技术和策略;- 内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等。
测试用例的元素
- 测试用例必须给出测试测试目标、测试对象、测试环境要求、输入数据和操作步骤, 概括为 5W1H。
- 测试目标:Why——为什么而测?功能、性能、可用性、容错性、兼容性、安 全性等。
- 测试对象:What——测什么?被测试的项目,如对象、函数、类、菜单、按 钮、表格、接口、整个系统等。
- 测试环境:Where——在哪里测?测试用例运行时所处的环境,包括系统的配 置和设定等要求,也包括操作系统、浏览器、通讯协议等单机或网络环境。
- 测试前提:When——什么时候可是测?测试用例运行时所处的前提或条件限 制。
- 输入数据:Which——那些数据?在操作时,系统所接受的各种可变化的数据, 如数字、字符、文件等。
- 操作步骤:How——如何测?执行软件和程序的先后次序步骤等。如打开对话 框、点击按钮等。 二、 为什么需要测试用例
- 测试用例是测试人员在测试过程中的重要参考依据。
- 测试用例可以帮助实施有效的测试,所有被执行的测试都是有意义的,不要执行毫无意义的测试操作。
- 良好的测试用例不断地被重复使用,使得测试过程事半功倍。 - 在软件产品的开发过程中,开发人员不断的推出新的版本,测试人员需要对原有功能进行多次的回归测试,即使在一个版本中,也要进行 2~3 次的回归测试。这些回归测试,就要求能重复使用测试用例。
- 测试用例是一个知识积累的过程。
- 测试用例是一个知识传递的过程,能保持一致、稳定的测试质量
- 从项目管理的角度来说,测试用例的通过率是检验代码质量保证效果最主要的指标之一。
- 测试用例也可以作为评估测试人员进度、工作量以及跟踪/管理测试的工作效率的主要因素,从而更加合理地做出测试安排或调整。
测试用例的写作说明
测试用例的模板/格式
测试用例的写作说明
用例编号/序号
简单、唯一。
用例说明/测试点
- 也称测试点、检查点、测试概述、用例概述、测试说明;
- 用一句话对测试用例进行概述;
- 可以总结测试目的;
- 可以用疑问句表示;
- 可以用“检查、验证、测试”等字眼(如验证 QQ 默认安装);
- 最好看到这句话就能知道如何测试;
- 尽量唯一(决策表可能会有重复的测试说明);
- 用例执行多轮时,越往后执行可能越快,如果用例写得好,直接看概述就行。
初始条件
- 也称预置条件、前提条件;
- 初始条件要是一个状态,而且是静态的,如管理员已登录后台;
- 初始条件是第一步操作步骤之前的状态,不能太远,不用从头写到尾
- 很多项目中不写预置条件。
操作步骤
- 若对数据要求高,需要把数据分离出来;
- 步骤要都有序号;
- 每一步用分号分开,最后用一个句号;
- 每一步必须换行;
- 参数前加冒号(如,用户名:admin);
- 涉及按钮界面用【】、“”等成对符号间隔;
- 功能的详细用例步骤 4-6 步左右;
- 最后一步一定是个动作,不能写结果。
预期结果
- 是一个状态;
- 如果参考文档中有描述,原封不动的抄过来;如果文档中没有具体要求,则点要一 致,可以有几个点,如 QQ 默认安装,应能启动、默认选项匹配等。
用例状态
- 通过、失败、阻塞、未执行、搁置、无效用例…
- 初始条件达不到时,一般用例状态为阻塞。
- 看如何执行用例,执行完关心什么来定。
优先级
- 用例的执行顺序。
案例/模板
测试用例的优先级
优先级的分类
如何设置测试用例的优先级
- 考率成本、时间、人员等因素
- 考虑用例的关联性
- 考虑用例的干扰性
- 决定执行用例的先后顺序
注意事项
- 兼顾测试充分性和效率
- 考虑测试执行的可再现性
测试用例的评审和管理
保证测试用例质量的方法
- 首先,要对用户需求、服务质量要求、产品特性有深刻且全面的理解
- 其次,采取正确、恰当的方法进行用例设计;
- 再者,按照测试用例的标准格式或规范的模板来书写测试用例;
- 最后,对测试用例的检查、评审,也是提高测试用例质量的主要且有效的手段。
测试用例评审要点
- 根据检查单或检查表(check-list)进行评审。 - 用例“文字校对”:错别字、病句、语句不通顺、含义不清晰、语义有歧义、格式不一致、标点不一致、中英文混合等。- 用例质量:遗漏用例、冗余用例、不清晰用例、错误用例、不可测用例等
- 确定用例的优先级
- 规划服务器和客户机
- 用例的分工执行与人员安排
- 记录评审过程,记录测试环境规划
测试用例的维护
- 原因:
- 通常情况下,测试用例需要更新,可能有以下几个原因: - 先前的测试用例设计不全面或不够准确。- 所发现的严重的软件缺陷没有被目前的测试用例所覆盖。- 编写的测试用例不规范或者语句错误- 新的版本中有新功能的需求或者原有功能的增强而需要发生改动- 旧的测试用例已经不再适用,需要删除
- 测似用例管理工具
- Excel
- Bugfree
- ZenTao(禅道,缺陷管理工具)
- ALM/QC(软件生命周期管理工具)
用例设计与编写方法总结
通过测试
- 主要用于验证系统和它陈述的需求一致,确定软件至少能做什么,一般通过分析需求说明书来设计测试用例。
失败测试
- 纯粹为了破坏软件而设计和执行的测试案例, 也称迫使出错测试。主要用于证明“一个系统不会做不需要它做的事”。
随机测试
- 也称即兴测试(ad hoc testing),是指临时准备的即兴的bug搜索过程。
- 缺点: - 无法度量随机测试的实际覆盖率- 许多测试都是冗余的- 测试数据因为都是随机的,重复测试使不可能的。
应用集群效应
- 找到的软件缺陷越多,说明那里的软件缺陷越多
- 程序员倾向于修复报告出来的问题。
探索性测试
含义:
- 是一种测试思维技术
- 是一种精致的、有思想的过程。
- 强调测试设计和测试执行的同时性。
- 测试人员通过测试不断学习被测系统,同时把学习到的关于软件系统的更多信息通过综合的整理和分析,创造出更多关于测试的注意。
- 测试设计,测试执行,测试日志的记录似乎是无关紧要的工作。
- 测试人员必须根据测试章程在规定时间内完成。
适合场所
- 没有或只有少量的有价值的文档
- 常用于在时间压力下
- 为补充适合的、正式和形式化测试。
如何选择用例设计和编写方法(重)
- 先使用大纲法拆分功能;
- 再使用场景法(基本流和备选流)、决策表设计测试用例
- 如果程序的功能说明中含有输入条件的组合情况,则应在一开始就选用决策表法。
- 用等价类划分方法、边界值分析方法、错误猜测法补充测试用例。
- 执行测试时进行探索性测试或随机测试
- 执行完测试用例后进行随机测试
提交缺陷报告
软件缺陷的判定
- 什么是缺陷
- 软件存在着不符合质量需求或违背软件用户、客户、企业意愿的问题,这就是软件缺陷 (Defect),又叫“Bug(臭虫)”。
- 软件缺陷的判定准则
- 软件未达到产品说明书标明的功能;
- 产品说明书简称为说明(spec)或产品说明(product spec),是软件开发小组的一个协定。它对开发的产品进行定义,给出产品的细节、如何做、做什么、不能做什么。这种协定从简单的口头说明到正式的书面文档有多种形式。
- 软件出现了产品说明书指明不应该出现的错误; - 如金融软件 7*24 工作不能宕机
- 软件功能超出产品说明书指明范围;
- 软件未达到产品说明书虽未指出但应达到的目标; - 如软件在断电时的意外处理
- 软件测试员认为软件难以理解、不易使用、运行速度缓慢,或者最终用户认为不好。 - 主要体现在易用性方面。
- 软件缺陷的表现形式
- 用户要求的功能、特性没有实现或部分实现。
- 运行出错,包括运行中断、系统崩溃、界面混乱等。
- 数据结果不正确、精度不够、不完整或格式不统一。
- 文字显示内容不正确或拼写错误。
- 系统性能低下、系统资源浪费。
- 分离和再现软件缺陷
- 发现缺陷后,应该做好分离和再现,排查发现的“缺陷”是不是软件本身的问题, 然后才能提交。
- 再现 3 次 - 重现- 复现
- 避免提交缺陷的缺陷和重复缺陷
- 缺陷的缺陷 - 是测试人员提交的不是缺陷的缺陷;- 是一种无效缺陷;- 此类缺陷常使测试人员遭受指责;- 怎么办:正确理解需求,做好复现。
- 重复缺陷 - 同一个缺陷 A 测试工程师提交后,B 测试工程师又提交或者自己提交的缺陷与之前提交的缺陷相同或类似;- 是一种无效缺陷;- 尽量避免两个人同时测试同一模块;- 自己提交的缺陷与自己的重复,提交前查找一下,增强开发知识。
- 处理无法再现的缺陷
- 首先,对这样的缺陷进行详细的记录,使用不同办法去尝试复现。
- 其次,要合理地安排时间,要考虑到测试项目的整体进度,对一时难以再现的缺陷 可以暂时搁置,以保证项目的正常进度,并尽快提交给开发人员。
- 最后,在测试过程中对未再现缺陷予以关注。
- 处理有争议的缺陷
- 跟有关人员进行沟通、讨论;
- 搁置。
提交缺陷报告
- 什么是缺陷报告
缺陷报告是对缺陷进行记录、分类和跟踪的文档。
- 缺陷报告的读者对象
- 软件开发人员 - 报告缺陷是为了缺陷得到修复。- 希望获得缺陷的本质特征和复现步骤。
- 质量管理人员、市场人员、技术支持人员 - 希望获得缺陷的严重程度和分布情况,以及对市场和用户的影响程度。
- 缺陷报告的写作准则(5C)
- Correct(准确) - 每个组成部分的描述准确,不会引起误解;
- Clear(清晰) - 每个组成部分的描述清晰,易于理解;
- Concise(简洁) - 只包含必不可少的信息,不包括任何多余的内容;
- Complete(完整) - 包含复现该缺陷的完整步骤和其他本质信息;
- Consistent(一致) - 按照一致的格式书写全部缺陷报告。
- 缺陷报告的组织结构
- 缺陷的标题/缺陷摘要/缺陷概述/缺陷基本信息
- 预处理
- 复现步骤
- 期望结果
- 实际结果
- 缺陷的严重程度:破坏程度
- 缺陷的优先级:解决的优先级
- 测试的软件和硬件环境
- 测试的软件版本
- 缺陷的类型
- 注释文字和缺陷截图
- 缺陷报告的写作要求
- 缺陷标题: - 尽量按缺陷发生的原因与结果的方式书写; - 执行完 A 后,发生 B;- 在什么地方,做了什么事情,出了什么结果; - 使用“在…以后”,“在…时候”或“在…期间”等连结词有助于描 述缺陷的原因和结果。- 避免使用模糊不清的词语;- 为了方便搜索和查询,尽量使用关键字;- 为了便于他人理解,避免使用术语、俚语或过分具体的测试细节。
- 复现步骤: - 提供测试的预备步骤和信息;- 步骤完整,准确,简短,没有缺漏任何操作步骤,没有任何多余的步骤;- 将常见步骤合并为较少步骤;- 简单地一步一步地引导复现该缺陷;- 每一个步骤尽量只记录一个操作;- 每一个步骤前使用数字对步骤编号;- 尽量使用短语和短句,避免复杂句型和句式;- 只记录各个操作步骤是什么,不要包括每个步骤的执行结果。
- 预期结果- 软件应该具有的结果,或者说正确结果应该是什么样子。
- 实际结果- 实际结果的描述要列出具体的表现行为,而不是简单的指出“不正确”或“不起作用”。- 如果一个动作产生彼此不同的多个缺陷结果,或者一个动作将产生一个结果,而这 个结果又产生另一个结果。为了易于阅读,这些结果应该使用数字列表分隔开来。 如实际结果: - 1.显示“命令代码行…错误”;- 2.显示“并且终止…服务”。
- 注释/截图- 可以包含以下各方面的内容: - 截取缺陷特征图像文件;- 测试过程所使用的测试文件;- 测试附加的打印机驱动程序;- 再次描述重点,避免开发人员将缺陷退回给测试人员补充更多信息;- 再次指明该缺陷是否在前一版本已经存在;- 多个平台之间是否具有不同表现;- 注释包含缺陷的隔离信息,指出缺陷的具体影响范围。- 如,缺陷的注释可能包含下面的内容: - 能在 Win2000 和 WinXP 文本框中显示文本内容,但不支持 Win98- 屏幕刷新后,现象会消失。- 使用二进制文件,不存在该错误。- 参见附加的使用说明书和测试文件。
- 怎么提交高质量的缺陷报告
- 尽早提交缺陷报告。
- 清楚地说明此问题对用户价值的危害。
- 提供尽可能多的技术信息(如包含复现该缺陷需要的环境变量或测试所用的数据文件),方便程序员调试。
- 报告的软件缺陷进行了必要的隔离,报告的缺陷信息具体、准确。
- 易于搜索软件测试报告的缺陷。
- 一个缺陷报告中只报告了一种缺陷。
- 缺陷报告中不要提问题。
- 避免常见的错误 - 我(I)、你(You)、他/她(He/She)- 情绪化的语言和强调符号!!!- 似乎(Seems)- 看上去可能(Appears to be)- 认为比较幽默的内容- 不确定的测试问题(Issues)/ 不确定是否是缺陷
缺陷的分类
缺陷的分类标准
根据缺陷类型对缺陷分类
- 功能缺陷
- 界面缺陷
- 文档缺陷
- 代码缺陷
- 算法错误
- 性能缺陷
根据缺陷的等级对缺陷分类
- A类–致命缺陷,包括以下各种错误: - 由于程序所引起的死机,非法退出;- 死循环;- 数据库发生死锁;- 因错误操作导致的程序中断;- 功能错误;- 与数据库连接错误;- 数据通讯错误
- B类–严重缺陷,包括以下各种错误: - 程序错误;- 程序接口错误;- 数据库的表、业务规则、缺省值未加完整性等约束条件
- C类–一般缺陷,包括以下各种错误: - 操作界面错误(包括数据窗口内列名定义、含义是否一致);- 打印内容、格式错误;- 简单的输入限制未放在前台进行控制;- 删除操作未给出提示;- 数据库表中有过多的空子段
- D类–较小缺陷,包括以下各种错误: - 界面不规范;- 辅助说明描述不清楚;- 输入输出不规范- 长操作未给用户提示;- 提示窗口文字未采用行业术语;- 可输入区域和只读区域没有明显的区分标志
- E类 – 意见或建议
根据缺陷处理的优先级对缺陷分类
根据缺陷状态对缺陷分类
缺陷报告的处理
缺陷报告的简单处理流程/缺陷的生命周期
- 软件测试人员提交缺陷报告;
- 测试负责人审核后将缺陷报告分配给相关的开发人员修改;
- 缺陷被修改后由测试人员根据缺陷报告中的修改记录进行返测;
- 返测通过的缺陷报告由负责人关闭,返测未通过的缺陷报告直接返回开发人员重新修改,缺陷报告直到缺陷被修复以后才关闭;
- 关闭或已解决的缺陷报告可能会被阶段性的复审重新打开,这些报告一旦被再次打开应该立即处理。
缺陷报告的标准处理流程
- 正常缺陷
- 重复缺陷
- 无效缺陷
- 推迟修改
- 验证不通过
- 描述不清楚
缺陷跟踪管理系统/缺陷管理工具
缺陷管理工具的功能
- 缺陷提交
- 缺陷跟踪
- 缺陷分析 - 有效的缺陷分析不仅可以评价软件质量,同时可以帮助项目组很好地掌握和评估软件的研发过程,进而改进研发过程,未对缺陷进行分析就无法对研发流程进行改进。- 缺陷分析还能为软件新版本的开发提供宝贵的经验,进而在项目开展之前,指 定准确、有效的项目控制计划,为开发高质量的软件产品提供保障。
常见缺陷管理工具
- Bugzilla
- Bugfree
- Mantis
- Jira
- ZenTao(禅道)
- Quality Center/Application Lifecycle Management - 目前市场占用率最高的项目管理工具。- 全球最大的测试工具提供商 Mercury Interactive 公司生产的企业级项目管理工 具。
测试方法
测试方法的分类
- 静态测试方法
- 动态测试方法
动态测试方法
- 通过运行程序来发现缺陷的测试方法。 - 黑盒测试- 百盒测试
黑盒测试
- 也称为功能测试、数据驱动测试、基于规格说明书测试。
- 从用户观点出发,主要以软件规格说明书为依据,对程序功能和接口进行测试,对输入输出数据之间的对应关系进行测试。
- 它不涉及到程序的内部结构,如果外部特性本身有问题或规格书明书有问题,则无法察觉 - 安全性测试、互操作性测试也属于功能测试。- 方法如场景法、等价法、边界值、因果图、决策表、错误猜测等。
- 黑盒测试还用于测试软件的非功能性特性。 - 非功能测试用于测试系统工作的怎么样,包括但不仅限于 - 可用性/可靠性/稳定性/健壮性/可恢复性测试- 可维护性测试- 易用性测试- 可移植性/兼容性测试- 配置测试- 文档测试- 国际化测试/本地化测试- 当不涉及程序内部结构时,上述测试类型也使用黑盒测试方法。
白盒测试
- 也称结构测试、逻辑驱动测试、基于程序本身的测试、程序员测试。
- 结构测试需要完全了解程序结构和处理过程,按照程序内部逻辑测试程序,检验程 序中每条通路是否按照预定要求工作。
黑盒测试与白盒测试的区别
静态测试方法
- 不执行程序的测试方法
- 主要用于测试 文档和代码(文档)。
- 静态测试方法包括评审和静态分析方法。
评审
评审的含义、过程和目的
评审的角色
评审的分类
- 文档审查
- 代码审查
- 代码走查
代码审查
- 代码审查的含义、过程和目的
- 代码审查的方法和范围
- 具体做法方法 - 互查
- 通常合格的代码应具备正确性、清晰性、规范性、一致性和高效性,概括起来, 代码审查的工作涵盖下列方面 - 业务逻辑的审查- 算法的效率- 代码风格 if(1 == j)与if(j == 1),问:以上哪种代码风格较好?第一种 if (j>MAX_NUM) 与 if (j>2000),哪个好?第一种
- 编程规则
代码走查
静态分析方法
数据流分析
- 使用了未声明/定义的变量
- 变量声明了没有使用
控制流分析
复杂度分析
- 复杂度分析给出一组能描述程序代码的复杂度特征的度量。
静态分析的意义
静态测试可以发现的缺陷
- 引用一个没有定义值的变量
- 从未使用的变量
- 模块和组件之间接口接口不一致
- 不可达代码或死代码
- 违背编程规则
- 安全漏洞
- 代码和软件模型的语法错误
一些静态分析工具
[OSS]代表开源软件,[PROPRIETARY]代表付费软件。
白盒测试方法
单元测试用例的设计方法
- 白盒测试方法
- 黑盒测试方法
- 以百盒测试方法为主,并适当地结合黑盒测试方法
白盒测试方法
- 逻辑覆盖法- 语句覆盖- 判定覆盖- 条件覆盖- 判定-条件覆盖- 条件组合覆盖
- 路径覆盖法
白盒测试方法的步骤
获得需求、获得/画出程序流程图/算法图
画出控制流图
- 根据需求来画
- 根据算法图/流程图来画
- 弄清预期结果
- 例子:
选择覆盖方法设计测试用例
语句覆盖法 C0
- 目标:程序中的每个可执行语句至少被执行一次。(尽量不重复)
- 度量(覆盖率)- 被执行的语句数 / 所有可能的语句数- 被执行的路径数 / 所有可能的路径数
- 例子:- a = 2,b = 1,c = 6- 用例对语句的覆盖率:100%- 用例对路径的覆盖率:25%
- 语句覆盖能发现语句错误
- 语句覆盖不能发现逻辑错误/条件错误
分支 / 判定 覆盖 C1
- 目标:程序中的每个判定的取真分支和取假分支至少被执行一次。
- 用例:- a=2,b=1,c=6- a=-1,b=1,c=1- 用例对语句的覆盖率:100%- 用例对路径的覆盖率:50%
- 分支/判定覆盖能发现逻辑错误
- 分支/判定覆盖不能发现组合判断中的条件错误
条件覆盖 C2
- 目标:程序每个判定中每个条件的可能取值至少满足一次。
- 未必比 C1 更全面。
- 不能发现逻辑错误。
- 用例:
判定-条件覆盖C1+C2
- 目标:每个条件中的所有可能取值至少执行一次,同时,每个判定的可能结果至少执行一次。
- 可能会导致某些条件掩盖了另一些条件
- 案例:
- 用例:
条件组合覆盖 / 多条件覆盖 C3
- 目的:每个判定中所有的条件取值组合至少执行一次。
- 比C2全面
- 用例:
路径覆盖 C4
- 目标:用例覆盖程序中的所有可能的执行路径。
- 不切实际- 因为涉及到相当长和无穷无尽的路径数。- 任何可能的循环在程序段中都被视为是可能的路径。
- 用例:
- 路径覆盖优化- McCabe的基路径方法- 从源节点到汇节点的线性独立路径数(根据圈复杂度计算) - V(G)=e-n+2p=10-7+2=5 或者 闭合环数+1- 当规模很小时,我们可以直观地标识独立路径。- 以下给出的是用节点/边序列表示的路径: - p1:A,B,C,G/1,4,9- p2:A,B,C,B,C, G/1,4,3,4,9- p3:A,B,E,F,G/1,5,8,10- p4:A,D,E,F,G/2,6,8,10- p5:A,D,F,G/2,7,10- 案例:
白盒测试工具
- 内存资源泄漏检查工具 - 如 Numega 中的 BounceChecker,Rational 的 Purify 等;
- 代码覆盖率检查工具 - 如 Numega 的 TrueCoverage , Rational 的 PureCoverage ,TeleLogic 公 司 的 Logiscope;
- 代码性能检查工具 - 如 Logiscope 和 Macabe 等。
- 静态源代码分析工具 - 类似于编译器,能够检查源代码,发现违反编程语言语法规则和大量定义编程规范的代码。
使用JUnit进行单元测试
JUint 简介
- JUnit是一个开放源代码的Java测试框架,用于编写和运行可重复的测试。
- JUnit测试是程序员测试,即所谓白盒测试,是一个Java语言的单元测试框架,多数Java的开发环境都已经集成了JNuit作为单元测试的工具。
- JNuit在极限编程和重构(refactor)中被极为推荐使用,因为在实现单元测试的情况下可以大大的提高开发的效率。
- 每编写完一个函数之后,都应该对这个函数的方方面面进行测试,这样的测试我们 称之为单元测试。 - 在编写大型程序的时候,需要写成千上万个方法或函数,也许我们在程序中只 用到该函数的一小部分功能,并且经过调试可以确定,这一小部分功能是正确 的。但是,我们同时应该确保每一个函数都完全正确,因为如果我们今后如果 对程序进行扩展,用到了某个函数的其他功能,而这个功能有 bug 的话,那绝 对是一件非常郁闷的事情。
JUnit 中的注解
- JUnit 使用注解进行单元测试。 - 注解用于修饰测试方法或测试类,写在测试方法或测试类的前面。同时,使用这些注解时,需要导入相应的包。
- 比较重要的注解大致有 Fixture 注解、@Test 注解、@Ignore 注解、@Parameters 注 解、@RunWith 注解。
Fixture 注解
- 表示“在某些阶段必然被调用的代码”。
- 一般包括@Before 注解、@After 注解、@BeforeClass 注解、@AfterClass 注解,这些注解一般用于修饰测试方法,测试方法名随意。
- @Before 注解 - @Before 修饰的方法在每个测试方法之前执行。
- @After 注解 - @After 修饰的方法在每个测试方法之后执行。
- @BeforeClass 注解 - @BeforeClass 修饰的方法在所有测试方法执行之前执行。
- @AfterClass 注解 - @AfterClass 修饰的方法在所有测试方法执行之后执行。
@Test 注解(重要)
- @Test 注解 - 用于修饰测试方法,表示要对被测试类的某个或某些方法进行测试。
- @Test(timeout=xxx)注解 - xxx 表示时间,以 ms 为单位;- 一般称为限时测试或超时测试,用于设置当前测试方法在一定时间内运行完, 否则返回错误。 - 对于那些逻辑很复杂,循环嵌套比较深的程序,很有可能出现死循环,因此一定要采取一些预防措施,限时测试是一个很好的解决方案,给测试函数或方法设定一个执行时间,超过了这个时间,程序就会被系统强行终止, 并且系统还会汇报该函数结束的原因是因为超时,这样就可以发现这些 Bug了。
@Ignore 注解
- @Ignore 注解用于修饰测试方法,表示忽略测试用例;
- 其含义是“某些方法尚未完成,暂不参与此次测试”。这样的话测试结果就会提示你有几个测试被忽略,而不是失败。一旦你完成了相应函数,只需要把 @Ignore 标注删去,就可以进行正常的测试。
@Parameters 注解
- 用于修饰产生数据集合的方法,用于参数化。
- 测试时,可能需要测试大量不同的路径,从而要使用大量的数据,使用@Parameters 注解只需要编写一个测试代码即可众多数据进行多次测试。
@RunWith 注解
- 用于指定一个测试运行器(Runner),@RunWith 用来修饰类,而不能修饰函数。
- 只要对一个类指定了 Runner,那么这个类中的所有函数都被这个 Runner 来调用。
- 常用的内置测试运行器有 Parameterized(参数化数据)和 Suite(测试集)。
JUnit 中的方法
断言
- 用来断定程序中是否存在缺陷。
- assertEquals(预期结果,实际结果) - 用于测试期望结果的断言,即测试两个对象是否相等,这个方法使用非常多。
- fail(错误消息内容) - 其中错误消息可选,假如提供,将会在发生错误时报告这个消息。该断言会使测试立即失败,通常用在测试不能达到的分支上(如异常)。
setUp 和 tearDown
- 在实际的测试中我们测试某个类的功能是常常需要执行一些共同的操作,完成以后需要销毁所占用的资源(例如网络连接、数据库连接,关闭打开的文件等),JUnit 提供了 setUp 方法、tearDown 方法、setUpBeforeClass 方法、tearDownAfterClass 方法。
- setUp 方法 - 在每个测试方法之前都会运行。- 主要实现测试前的初始化工作。
- tearDown 方法 - 在每个测试方法结束以后都会执行。- 主要实现测试完成后的垃圾回收等工作(复原)。
- setUpBeforeClass 方法 - 在所有测试方法执行之前执行。
- tearDownAfterClass 方法 - 在所有测试方法执行之后执行。
- 实际使用时,setUp 方法可用@Before 注解代替,tearDown 方法可用@After 注解代 替,setUpBeforeClass 方法可用@BeforeClass 代替,tearDownAfterClass 方法可用 @AfterClass 代替。
JUnit 的安装和使用流程(以idea为例)
第 1 步,新建 Java 项目
为项目命名,新建一个包并命名test,新建类并命名(也可以暂时不建类,这个类是被测类),如下图。
第 2 步,将 JUnit 引入项目(导入junit.jar包)
打开菜单File => 点击Project Structure
选择Modules => 点+号
弹出对话框,选择JARs or Directories
找到idea的安装目录lib下,选择junit4的jar包
第 3 步,编写被测类的代码
这是一个能够简单实现加减乘除、平方、开方的计算器类,然后对这些功能进行单元测试。编写完成后,类无需编译。
publicclassCalculator{publicint result=0;publicintadd(int operand1,int operand2){
result=operand1+operand2;//将两个传入参数进行相加操作return result;}publicintsubtract(int operand1,int operand2){
result=operand1-operand2;//将两个传入参数进行相减操作return result;}publicintmultipe(int operand1,int operand2){}publicintdivide(int operand1,int operand2){
result = operand1/2;//错误return result;}publicvoidclear(){//将结果清零
result =0;}publicvoidsquare(int operand1){
result = operand1 * operand1;}publicintgetResult(){returnthis.result;//返回计算结果}}
第 4 步,创建 JUnit 测试用例类
有两种方法,第一种直接点击被测试类Calculator使用 Ctrl+Shift+T;第二种 右键点击界面->generate->test…
在打开的窗口中选择“新建 JUnit 测试”,这里使用注解方式编写测试方法
测试类(如 CalculatorTest)是一个独立的类,没有任何父类。 测试类的名字可以任意命名,没有任何局限性,所以我们不能通过类的声明来判断它是不是一个测试类,它与普通类的区别在于它内部的方法的声 明。
在下图中选择需要测试的方法,在前面打勾。
之后系统会自动生成一个新类 CalculatorTest,里面包含一些空的测试用例, 之后需要对这些测试用例进行修改才可使用。如下图所示。
第 5 步,运行测试代码
在步骤 4 的基础上编写测试代码(这里暂时不编写,后文给出代码),右击 CalculatorTest 类,选择运行。
第 6 步,分析测试结果
- 表示共进行了 5 个测试,其中 0 个测试代码出现错误,5个测试成功,共花费3ms。
JUnit 单元测试案例
在测试类中创建一个被测类对象
privatestaticCalculator cal =newCalculator();
使用@Test 进行测试
这里以测试 Calculator 类的 add 方法、测试 substract 方法和divide 方法为例进行说明。
publicvoidtestAdd(){
cal.add(2,2);assertEquals(4,cal.getResult());//fail("Not yet implemented尚未实现");}
- 其中@Test 表示其后的方法 testAdd 是测试方法。
- 对于测试方法的声明有如下要求 :名字可以随便取,没有任何限制,但是返回值必须为 void,而且不能有任 何参数。
- 使用 assertEquals(4, calculator.getResult())表示判断结果 result 是否等于 4。
- 测试结果:
@TestpublicvoidtestDivide(){
cal.divide(4,1);assertEquals(4, cal.getResult());}
说明:
- cal.divide(4,1)表示将 4 除以 1 后放入 result 中,最后 result 应该等于 4;
- 使用 assertEquals(4, calculator.getResult())表示判断结果 result 是否等于 4。
- 测试结果:
- 表示预期结果是 4,实际结果是 2,测试没有通过。
@TestpublicvoidtestSubtract(){
cal.subtract(4,2);assertEquals(2,cal.getResult());//fail("Not yet implemented");}
- cal.subtract(4,2);表示将 4 减 2 后放入 result 中,最后 result 应该等于 2;
- 使用 assertEquals(4, calculator.getResult())表示判断结果 result 是否等于 4。
- 测试结果
使用@Before 进行测试前准备
加入@Before 注解
在 CalculatorTest 类中添加一个方法,用于在执行每个测试方法前先将 result 变量的值清零。代码如下:
@Beforepublicvoidinitiate(){
cal.clear();}
在 CalculatorTest 类中添加一个方法setUp(),用于在执行每个测试方法前输出“测试开始”。代码如下:
@BeforepublicvoidsetUp()throwsException{System.out.println("测试开始");}
使用@Ignore 忽略测试
multipe 方法并没有编写方法体,可以使用@Ignore 忽略该测试。测试代码如下。
@IgnorepublicvoidtestMultiply(){fail("代码未实现,暂时不测");}//另一种写法@Ignore("代码未实现,暂时不测")@TestpublicvoidtestMultiply(){}
测试结果:注意:方法一直接不显示
使用@Test(timeout=?)进行超时限制测试
当方法中使用循环时,使用@Test(timeout=?)可以测试方法中的循环是否陷入了死循环。测试代码如下:
@Test(timeout =2000)publicvoidtestDivide1(){for(;;);}
测试结果:
- timeout 的单位是毫秒,根据具体情况设置此时间即可。
使用@RunWith 和 @Parameters 进行参数化(多轮)测试
什么是参数化
- 怎么测试多分支? - 如一个对考试分数进行评价的函数 - 返回值分别为“优秀,良好,一般,及格,不及格”- 在编写测试的时候,如果编写 5 个测试方法,进而测试 5 种情况,是一件很麻烦的事情。
- 为了简化类似的测试,JUnit 提出了“参数化测试”的概念,只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。
创建用@RunWith(Parameterized.class)注解的测试类
继续使用先前的例子,测试函数 square,其代码如下:
publicvoidsquare(int operand1){
result = operand1 * operand1;}
这里假设暂且测试三类数据:正数、0、负数:
- 若使用参数化测试,必须指定一个 Runner,这个 Runner 就是 Parameterized, 其写法是@RunWith(Parameterized.class)。
- 必须生成一个新的测试类,不能与其他测试共用同一个类;
- 必须在类前使用@RunWith(Parameterized.class) 指定运行器为Parameterized;
- 在类中创建一个 Calculator 的对象以便调用其被测试的方法。 这里假设新建测试类命名为 SquareTest,代码如下:
@RunWith(Parameterized.class)//注意包含相应的包publicstaticclassSquareTest{privatestaticCalculator calculator=newCalculator();}
在新测试类中添加存储参数的成员变量
- 在类中定义两个变量,一个用于存放参数,一个用于存放期待的结果。 private int param; private int result;
使用@Parameters 修饰测试数据集方法
- 下面编写获得测试数据集的方法,该方法必须使用@Parameters 标注进行修饰; - 方法可以任意命名;- 集合中数据的顺序无所谓,但编写该类的测试人员必须记住它们的意义。 下面的代码中第 1 个数字表示参数,第 2 个表示预期结果。
@ParameterspublicstaticCollectioncaseData(){returnArrays.asList(newObject[][]{{2,4},{0,0},{-3,9}});}
编写类的构造函数
- 功能是对先前定义的两个参数进行初始化。 - 注意参数的顺序要和上面的数据集合的顺序保持一致。 - 如果前面的顺序是{参数,期待的结果},那么构造函数的顺序也要是 “构造函数(参数, 预期结果)”。
- 代码如下:
//构造函数,对变量进行初始化 publicSquareTest(int param,int result){this.param=param;this.result=result;}
编写测试方法
代码如下
@TestpublicvoidsquareTest(){
calculator.square(param);assertEquals(result, calculator.getResult());}
测试结果:
读取文件中的数据进行参数化
- 打开文件 - File file = new File(文件路径) ;
- 读取文件 - FileReader bytes = new FileReader(file);- BufferedReader chars = new BufferedReader;
- 读取文件中的行 - while(row = chars.readerLine()) != null)
- 拆分行中的列 - row.spilt(“\t”)
- 关闭文件 - chars.close();
使用@RunWith 和 @Suite.suiteClasses运行测试集
什么是测试集
- 也称打包测试、测试套件
- 在一个项目中,只写一个测试类是不可能的,会写很多测试类,可是必须一个一个执行,比较麻烦
- JUnit 提供运行测试集的功能,将所有需要运行的测试类集中起来,一次性的运行完毕。
@RunWith(Suite.class) 和 @Suite.suiteClasses注解
- 打包测试也需要一个Runner,需要向@RunWith标注传递一个参数Suite.class
- 同时,还需要另一个标注@Suite.suiteClasses,来表明这个类是一个打包测试类,在内部需要提供运行的测试类的名字
- 代码如下:
@RunWith(Suite.class)@Suite.SuiteClasses({CalculatorTest.class, testsquare.class})publicclassAllTest{}
使用 JUnit 的注意事项
- 测试类和测试方法应该有一致的命名方案。
- 确保测试与时间无关,不要依赖使用过期的数据进行测试,导致在随后的维护过程中很难重现测试。
- 测试(测试量或代码规模)要尽可能地小,执行速度快。
- 不要硬性规定数据文件的路径。
- 利用 JUnit 的自动异常处理书写简洁的测试代码。
- 事实上在 JUnit 中使用 try-catch 来捕获异常是没有必要的,JUnit 会自动捕获异常,那些没有被捕获的异常就被当成错误处理。
版权归原作者 叁次 所有, 如有侵权,请联系我们删除。