什么是软件测试?
使用人工或自动手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求或是弄清预期结果与实际结果之间的差别。
为什么要进行软件测试?
- 软件总存在缺陷。只有通过测试,才可以发现软件缺陷。也只有发现了缺陷,才可以将软件缺陷从软件产品或软件系统中清理出去。
- 软件中存在的缺陷给我们带来的损失是巨大的,这也说明了软件测试的必要性和重要性。
- 测试是所有工程学科的基本组成单元,自然也是软件开发的重要组成部分。
- 测试人员水平越高,找到软件问题的时间就越早,软件就越容易更正,产品发布之后越稳定,收益越大。
软件质量
- 是反映实体满足明确的和隐含的需求的能力的特性的总和。
- 软件质量可以被解释为满足以下方面的需求
- 明确的(外在的):功能、易用性……
- 隐含的(内在的):可维护性、用户体验……
- 为了在软件开发过程中保障软件质量,我们需要在SDLC(Software Development Life Cycle, 软件生命周期:需求分析、系统设计、系统实现、测试、维护)的每个阶段都做到QA(Quality Assurance, 质量保证)
软件质量保证
SQA活动时通过对软件产品有计划地进行评审和审计来验证软件是否合乎标准的系统工程,通过协调、审查和跟踪以获取有用信息,形成分析结果以指导软件过程。
Testing和SQA的关系
SQA与软件测试之间相辅相成,既存有包含又存有交叉的关系。
SQA指导、监督软件测试的计划和执行,督促测试工作的结果客观、准确和有效,并协助测试流程的改进。
而软件测试是SQA的重要手段之一,为SQA提供所需的数据,作为质量评价的客观依据。
- 相同点:两者都是贯穿整个软件开发生命周期的流程。
- 不同点:SQA是一项管理工作,侧重于对流程的评价和监控;测试是一项技术性的工作,侧重对产品进行评估和验证。
Quality Assurance与Quality Control
- 相比于去发现缺陷,QA更倾向于去预防缺陷的产生。QA更注重制定生命周期中每个阶段用于保证质量的条例、规则,重在预防。
- QC是将产品与明确的标准进行比较的过程,如果发现不符合则采取行动,它更倾向于去发现缺陷,而不是预防缺陷。
什么时候开始软件测试?
- 越早越好。发现缺陷越早,返工的工作量就越小,所造成的损失就越小。
- 还要取决于开发模型。在瀑布模型中,测试只有等到程序完成了才可以执行,强调测试仅仅是对程序的检验。这是不符合当今软件工程的实际需求的。
- 在软件生命周期的每个阶段,测试以不同的方式进行。
什么时候结束软件测试?
软件测试是一个永不结束的过程。但也有例外,例如:
- 到了预定的测试期限。
- 测试用例执行完毕了。
- 功能和代码覆盖率达到一定的值时。
- 代码故障率低于某一个确定的水平,或者没有发现严重的bug时。
- 管理层的决定。
软件测试中描述软件出现的问题的术语
- Error(错误):发生在编写程序的过程中。
- Fault(故障):是一个或多个错误的表现,是一种内部状态。
- Failure(失效):发生在当错误的代码被执行时,会导致程序的输出是不正确的。
- Incident(事故):当软件失效时没有任何的显示信息。
- Defect(缺陷):所有的软件问题,可能存在于代码、数据或文档中,与用户的期望不一致的情况,如:函数不能正确地执行、运行缓慢、用户界面出现错乱……
Verification vs. Validation
验证是检验开发出来的软件产品和设计规格说明书的一致性。但设计过个说明书本身就可能存在错误,所以即使软件产品中某个功能实现的结果和设计规格说明书完全一致,但可能并不是用户所需要的。
因为设计规格说明书很可能一开始就对用户的某个需求理解错了,所以仅进行验证测试还是不充分的,还要进行确认测试。确认测试检验产品是否满足用户的真正需求。
软件产品 -验证-> 软件需求规格说明书
软件产品 -确认-> 用户期望、需求
- Verification(验证):静态的。软件需要符合它的软件需求规格说明书。是否正确地构建产品?
- Validation(确认):动态的。软件需要满足用户的期望和需求。是否构建了正确的产品?
Testing vs. Debugging
- Testing是去发现软件中的缺陷,但没有去修正它。
- Debugging是去发现、定位并修复软件中存在的问题。Debugging可以在开发阶段中进行单元测试的同时进行。
白盒测试
- 定义:又称为结构化测试或逻辑驱动测试,也就是已知产品的内部工作过程,清楚最终生成软件产品的计算机程序结构及其语句,按照程序内部的结构测试程序,测试程序内部的变量状态、逻辑结构、运行路径等,检验程序中的每条通路是否都能按预定要求正确工作,检查程序内部动作或运行是否符合设计规格要求,所有内部成分是否按规定正常运行。
- 缺点:
- 不能查出程序违反了设计规范,即程序在实现一个不是用户需要的功能。
- 不能查出程序中因遗漏路径而出错。
- 可能发现不了一些与数据相关的异常错误。
黑盒测试
- 定义:又称为数据驱动测试。在测试时,把程序看做一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,测试人员针对软件直接进行测试,检查系统功能是否按照需求规格说明书的规定正常使用、是否能适合地接收输入数据而输出正确的结果等,检查相应的文档是否采用了正确的模板、是否满足规范要求。
PDCA
Plan, Do, Check, Action
V模型
- V模型中,软件测试活动和项目同时启动,软件测试的工作很早就开始了。它能相对准确地反映测试与开发之间的关系,左边是软件定义和实现的过程,右边是对左边所构造的东西进行验证的过程,以确认是否满足事先的定义和要求。测试与开发有一对一的关系。
- 右边为UISA:U-单元测试,I-集成测试,S-系统测试,A-验收测试。
- 缺点:只注重动态测试而忽略了静态测试的好处和有效性。因此又拓展为W模型。
W模型
- W模型由两个V字型模型组成,分别代表测试与开发过程。
- 测试的对象不仅是程序,还包括需求定义文档、设计文档等(静态测试)。相比于动态测试,静态测试成本更低、更有效率。
- W模型认为测试过程和开发过程同样重要,既采用了静态测试又采用了动态测试。
测试的种类
- 方法划分:白盒测试、黑盒测试
- 测试阶段、层次划分:单元测试、集成测试、系统测试、验收测试
- 目标、特性划分:功能测试、健壮性测试、性能测试、适用性测试、安全性测试、可靠性测试
白盒测试 vs. 黑盒测试
白盒测试 | 黑盒测试 | |
---|---|---|
程序结构 | 已知程序结构 | 未知程序结构 |
规模 | 小规模测试 | 大规模测试 |
依据 | 详细设计说明、源代码 | 需求说明、概要设计说明 |
面向 | 程序结构 | 输入输出接口/功能要求 |
适用 | 单元测试 | 集成、系统、验收测试 |
测试人员 | 开发人员 | 专门测试人员/外部人员(用户) |
优点 | 能够对程序内部的特定部位进行覆盖 | 能站在用户的立场上进行测试 |
缺点 | 无法检验程序的外部特性,不能检测对需求的遗漏 | 不能测试程序内部特定部位,如果规格说明有误,则无法发现 |
为什么我们不能使用穷举测试?
- 时间代价太昂贵。
- 穷举路径测试不能发现程序中因为遗漏路径而导致的错误。
- 穷举路径测试可能发现不了一些与数据相关的异常错误。
白盒测试需要遵循的原则
- 一个模块的所有独立路径都至少测试一遍(基本路径测试)。
- 所有逻辑变量都要用真和假进行测试(逻辑覆盖)。
- 检查程序的内部数据结构,确保结构的有效性。(静态测试 + 数据流测试)
- 要对所有的循环进行测试(循环测试)。
- Run all cycles within operational range. (Loop testing)
逻辑覆盖
- Statement Coverage 语句覆盖
- 设计一系列的测试用例,使得每一处可执行语句至少被执行一次。
- 语句覆盖是最弱的逻辑覆盖。
- Decision Coverage 判定覆盖
- 设计一系列的测试用例,使得每一个判断语句的真和假分支都至少被执行一次。
- 如果是”Switch-Case”类型,则要求每个分支都至少被执行一次。
- 判定覆盖不能保证发现判断语句中错误的条件。
- Condition Coverage 条件覆盖
- 设计一系列的测试用例,使得每个判断中每个条件的可能取值至少取一遍。
- 满足条件覆盖不一定满足判定覆盖。条件覆盖不一定比语句覆盖、判定覆盖好。
- Condition/Decision Coverage 条件判定覆盖
- 它是判定和条件覆盖的交集,即设计一系列的测试用例,使得判断条件中的所有条件可能取值至少取一遍,同时,所有判断的可能分支都被执行一次。
- 无法发现And和Or互换的问题。
- Condition Combination Coverage 条件组合覆盖
- 设计一系列的测试用例,使得判断条件中的所有条件可能可能的组合至少取一遍,同时,所有判断的可能分支都被执行一次。
- 是最强的逻辑覆盖,但是不能保证覆盖到全部路径。
- Path Coverage 路径覆盖
- 设计测试用例,覆盖程序中的所有可能的、独立的执行路径。
- Complete Coverage 全覆盖
- 条件组合覆盖 + 路径覆盖
基本路径测试?
- 基本路径测试是路径测试和分支测试的混合。
- 路径测试:测试程序中所有或选择的路径。
- 分支测试:测试程序中每一个判断结点的输出路径。
如何设计基本路径测试的测试用例?
- 利用系统设计或者源代码,画出与之相符的控制流程图。
- 计算控制流程图的环路复杂度。
- 边数 - 结点数 + 2
- 判断结点数 + 1
- 闭合区域数 + 1
- 找出独立路径的集合,准备测试用例。
循环测试
循环测试中使用了黑盒测试的边界值分析方法,一个简单循环可以设计7个测试用例。设n为该简单循环最大的循环次数,则7个测试可以为: 0, 1, 2, m, n-1, n, n+1,其中m是一个典型值,即较为中间的一个数。
- 简单循环
- 使用上面的方法设计7个测试用例。
- 嵌套循环
- 从最内层的循环开始,将其他层循环设为最小可取值。
- 逐层向外设计,外层循环保持为最小可取值,内层循环设为典型值。
- 串联循环
- 不规则循环
数据流测试
- 数据流测试方法根据变量的定义、使用和删除的位置来选择测试路径。
- 数据流测试可以检测出由于不正确使用变量导致的错误。
~d | √ | ~u | x | ~k | x | dd | ? |
---|---|---|---|---|---|---|---|
du | √ | dk | ? | ud | √ | uu | √ |
uk | √ | kd | √ | ku | x | kk | x |
- 定义清除路径(definition clear, def-clear):对于一个变量v,路径中没有对v的重定义。
- 定义使用对(definition-use pair, du-pair):对于(d, u)这样一个数据结构,d是定义了变量v的结点,u是使用了v的结点或者路径,且d到u是定义清除路径。不要求定义清除路径是可达的。
- 全定义覆盖(All-Defs Coverage):对于程序中的每个变量,覆盖它每个的定义点,每个定义点至少要有一条定义清除路径。
- 全使用覆盖(All-Uses Coverage):对于程序中的每个变量,覆盖它的每一个定义点到它的每个使用点(包括p-use和c-use)。
简单路径&无环路
- 简单路径(Simple):所有边都不重复的路径。
- 无环路(Loop-free):所有结点都不重复的路径。
定义使用路径(du-path)
对于du-pair产生的路径:对于c-use,是简单路径;对于p-use,是无环路路径(注意最后一个结点重复是没问题的),则称它们是定义使用路径。
- All-DU-Paths:覆盖对于每一个变量的每一个定义到每一个使用的du-path。