Skip to main content

第08章 基于生命周期测试

第08章 基于生命周期测试

前面我们花了很长时间,讲解单元测试。我们所有的测试内容的话是以单元测试为基础的,单元测试我们可以用黑盒测试方法,部分的内容会集中到结构化测试内容。我们单元一个一个的测完以后,开发好了以后,后面的话还要到整个软件生命周期的管理里面去。

后面除了单元外了以后还有更重要的一些集成测试、系统测试。

一、开发模型

1)瀑布模型

  • 原来讲软件工程的时候,都会把瀑布式生命周期拿出来,批判的过程就是说它这个灵活性太差,然后引入到迭代开发过程里面去。但是实际上瀑布式的生命周期的话,其实对我们整个软件这个开发的生命周期来讲,它是一个非常长远的影响。

  • 编码之前的话,你有需求的说明,有概要的设计详细设计
  • 编码这个实现完了以后,我们就可以做单元测试
  • 单元测试完了以后我就要做集成测试,集成测试的话其实对应着概要的设计
  • 系统测试一般来讲是对应的整个一个软件的这个需求规格说明

所以可以看到每个测试的话,对于软件整个生命周期里面它有不同的测试的内容。

  • 从传统瀑布模型的观点:
    • 单元测试:面向详细设计,完成软件独立模块的测试
    • 集成测试:面向概要设计,完成软件模块之间的组合测试
    • 系统测试:面向需求分析,完成系统的功能测试
  • 瀑布模型的优点:
    • 瀑布模型框架非常适合层次管理结构
    • 每个阶段都有明确的产物,便于进行项目管理
    • 详细设计中分工明确,可以井行工作,缩短周期
  • 瀑布模型的缺点?
    • 需求规格说明与系统测试之间周期很长,无法加入客户反馈
    • 模型几乎排除了综合可能,最先发生在集成测试
    • 单元级别大规模并行开发可能会受到人员数量限制
    • 开发人员需要对系统 “完美”理解

2)瀑布模型变体

  • 增量开发模型:是将一个软件产品分成若干次产品进行提交,每一次新的软件产品的提交,都是在上次软住产品的基础上,增加新的软件功能,直到全部满足客户的需求为止
  • 演化开发模型:演化开发模型是在雷求分析之前,首先提供给客户或用户一个最终产品的原型(部分主要功能的软件)
  • 螺旋模型:它与瀑布模型和快速原型模型十分相似。但重要的是,它在每个阶段都增加了风险分析和验证这两个重要的步骤。

这三种派生模型的好处,是增加了迭代开发的方法,而不是将成功的风险全部放在了最后阶段!在这样的开发模型中,回归测试就成为一种重要的测试方法。回归测试 (Regression test)对已经完成 测试的软件进行修改和增加之后,重新测试软件。

3)敏捷开发

敏捷开发是软件开发⽅法的⼀个很⼤的范畴,包括Scrum、 极限编程(XP)、测试驱动(TDD)、适应性软件开发、结对编程等。核心思想是:以人为本,适应变化。

  • 敏捷价值观之敏捷宣言:

    • 个体和交互胜过过程和工具。人是软件项目获得成功最为重要的因素。合作、沟通能力以及交互能力比单纯的软件编程能力和工具更为重要。方法和工具是“死”的,人是“活”的,人要是协作不好,再强大的方法和工具都是“白扯”;
    • 可用的软件胜过完备的文档。
      • 过多的面面俱到的文档往往比过少的文档更糟
      • 软件开发的主要和中心活动是创建可以工作的软件
      • 直到迫切需要并且意义重大时,才进行文档编制
      • 编制的内部文档应尽量短小并且主题突出
    • 客户协作 胜过 合同谈判
      • 客产不可能做到一次性地将他们的需求完螫清晰地表述在合同中
      • 为开发团队和客户的协同工作方式提供指导的合同才是最好的合同
    • 响应变化胜过遵循计划
      • 变化是软件开发中存在的现实
      • 计划必须有足够的灵活性与可塑性
      • 短期迭代的计划比中长期计划更有效
  • 对比敏捷开发和瀑布模型

    • 瀑布模型:固定的、没有弹性的。很困难去达到互动。假如说需求没直完金的被了解,或是可能需要完全地改变项目的靈求,瀑布式的模型是比较不适合的。
    • 敏捷方法:完整地开发,每少数几周或是少数几个月里可以测试功能。强调在获得最简短的可执行功能的部分,能够及阜给子企业价值。在整个项目的生命周期里,以持续的改善、增加未来的功能。

4)XP活动(极限编程)

XP活动:倾听-测试-编码-设计。主要有12项的典型实践活动。XP 是一种轻量(敏捷)、高效、低风险、柔性、可预测、科学而且充满乐趣的软件开发方式。如下:

  • 现场客户:始终在开发团队中有一位客户。现场客户的工作:回答问题、编写验收测试、运行验收测试、指导迭代、接受版本
  • 计划游戏:计划是持续的、循序渐进的。每2周,开发人员就为下2周估算候选特性的成本。以业务优先级和技术估计为基础,决定下一版本发布的范围。
  • 系统隐喻:在XP中,隐喻是一种概念框架并提供名称的描述系统,类似于其他方法中的体系结构(或体系结构基准)。例子:Windows风格的界面、网上购物站点的购物车
  • 简单设计:系统设计尽可能简单
  • 代码集成所有:整个团队拥有所有代码。任何人都可以更改他们需要更改的部分。没有唯一对代码有所有权的人。
  • 结对编程:结对编程是让两个人共同设计和开发代码的实践。结对者是全职合作者,轮流执行键入和监视;这提供了持续的设计和代码评审。不是两个人做一个人的事情。
  • 积极影响:
  • 测试驱动:是我们敏捷开发里面就是说经常会提的一种软件开发的这个过程。结对或简单的设计以后,然后形成一个测试。(也就是先测试后编码)有时候一些需求本身的话很多,用户的这种一些功能的一些描述也好,它都是可以变成一个个测试用例的,通过测试去理解需求

  • 小型发布:XP推荐小而频繁有意义的发布,方便回滚
  • 重构:一个模块出来很多错误,这个东西怎么办,那就重构一个模块。重构确保对内对外输出不变。不是所有东西都要重构的。重构是XP的一个重要组成部分。所谓重构是指在不改变代码外在行为的前提下对代码做出的修改,以改进代码的内部结构。重构是一种有纪律的、经过训练的、有条不紊的代码整理方法,可以将整理过程中不小心引入错误的可能性降到最低。从本质上说,重构就是在代码写好之后改进它的设计。重构的节奏:重新推理、小的更改、重新推理、小的更改、重新推理
  • 持续集成:持续集成的思想是任何时候只有一项任务完成,就集成新代码,构造系统井测试。持续集成是每日构建\每晚构建的一种极限形式,是XP的重要基础。每日构建/每晚构建是将一个软件项目的所有最新代码取出,从头开始编译、链接,用安装软件包将链接好的程序安装好,运行安装后的软件,使用测试工具对主要功能进行测试,发现错误并报告错误的完整过程.让开发人员在第一时间了解到软件的错误,并迅速排除错误,是每日构建\每晚构建最重要的目标之一。每日构建、每晚构建必须出日志和报告,并发布构建结果的有关信息,最好能够使用自动化工具发出电子邮件通知。
  • 代码规范:养成统一的代码风格

XP的核心活动: 简单设计、测试先行、重构、持续集成

5)自动化测试

软件是⼀个不断迭代的开发过程,回归测试是软件测试的重要内容。但是,实际执⾏情况却不尽如⼈意,其主要原因是目前的回归测试通常都是 ⼿⼯测试。存在问题如下

  • 测试过程中,⼤量精⼒花在输⼊数据、执⾏程序和数据比较上,⽆法把精⼒集中到关键问题上。
  • ⼿⼯测试是⼀件⼯作量非常⼤的、重复的、枯燥的⼯作。
  • 现在的应用系统使用环境比较复杂,通常会运⾏在不 同的操作系统、数据库、中间件等系统软件上,很难 组织业务⼈员对所有环境进⾏测试。
  • 随着迭代开发越来越盛⾏,测试的频率增加了。传统 的⼿⼯测试已经满⾜不了软件开发的需求。
  • 参与测试的业务⼈员不⾜,⽆法保证充分的测试,也 ⽆法重复。

自动回归测试系统功能结构:自动回归测试系统在通用测试⼯具上构建了⼀ 个自动回归测试框架,框架里包含⼀个公用函数库和5个主要功能模块。通过自动回归测试框架,自动测试⼯程师可以完成测试用例设计和自动脚本⽣成功能,业务⼈员可以完成业务流定义和数据配置功能,测试执⾏⼈员可以完 成测试调度和测试管理功能

  • 测试用例设计:测试用例是最小的业务分支,它规定了需要操作的对象、步骤、动作和需要使用的数据。测 试用例是可复用的,因此在测试用例中的数据 应是参数化的,由此测试用例产⽣的测试脚本也是可复用的。测试用例应由业务⼈员和技术⼈员设计。业 务⼈员使用Excel或其它⼯具来设计,技术⼈ 员使用自动回归测试框架来设计。
  • 脚本⽣成器:脚本的维护是自动测试系统中维护⼯作量最⼤的部分。 在自动回归测试框架中,自动脚本⽣成器可以自动产⽣ 健壮的、结构化的、易于维护的脚本。
  • 业务流管理器:自动测试执⾏的实际上是⼀个⼀个的业务流,业务流是 由测试用例串联起来的,
  • 数据管理器:数据管理器提供为测试用例指定数据的功能。
  • 测试调度器:配置业务流的执⾏时间,支持预约测试,可选择业务流执⾏、执⾏测试、判断并记录测试结果。测试调度器设计,往往包括测试框架和测试环 境的设计与实现。

二、集成测试(白盒)

1)概念

将集成测试与系统测试分开?为什么

  • 集成测试针对的是模块之间的关系,这些模块基本上是我们做完单元测试以后形成的一些模块,那么它实际上也是一种结构化的测试,是一个 白盒测试 。而系统测试针对的是整个系统的功能,不需要了解程序的结构,所以是黑盒测试
  • 集成测试需要了解程序的结构,是一种结构化 的测试方法,有路径覆盖的含义。
  • 系统测试不需要了解程序的结构,是一种黑盒 的测试方法,是功能覆盖的意义。
  • 集成测试是由软件开发人员完成的;而系统测 试往往是需要用户的参与的。

2)集成测试方法

  • 自顶向下集成:从主程序(顶层)开始,所有下层程序都以 “桩程序”出现。完成顶层测试后,以真实程序代替 “桩程序”,向下进行下一层测试。“桩程序”(stub):就是模拟被调用程序的代码的输出。一般以表格形式存在,而不直接调这个代码本身。

  • 自底向上集成:从程序的最下层节点(叶子)开始,通过编写“驱动器”完成测试,然后以真实程序代替 “驱动器”,向上进行上一层测试。 “驱动器”:模拟对测试节点的调用驱动。

  • 三明治集成:是自顶向下和自底向上测试的组合,即可 以同时从顶和底向中间层集成,可以减少桩程序和驱动的数量。

  • 大爆炸测试:不分层次,将所有单元放在一起编译,并进行一次性测试。【缺点定位不准确,遇到问题很麻烦】

  • 以下图为例,如果我们要自顶向下集成,例如我写一个模拟中央银行通讯的桩程序,模拟读取写入数据。这样外部行为看上去就像中央银行通讯的模块,但是实现不管。

  • 以下图为例,如果我们要自低向上集成,从下往上,那就是先编写一个驱动器,比如编写一个模拟设备传感器与控制的,模拟调用通道传感与控制的系统

  • 思考问题:上图需要开发多少个桩程序?总节点的个数-根节点的个数

  • 思考问题:上图需要开发多少个驱动器?非叶子节点的数量。

  • 思考这个为什么是白盒测试?我们不管是Mock还是桩程序,都是需要去进行代码的替换。这个图叫做功能分解了以后,我们去开发相关的桩程序或者驱动器程序,所以说是白盒测试。

当然我们还可以基于调用图的集成,我们从模块之间的调用关系去看整个一个这个 ETM 这个例子。节点和节点之间存在调用和被调用的关系。能不能通过调用图之间的关系做相应的集成?

  • 成对集成:为减少桩程序和驱动器的开发,可采用调用对的测试方法。SATM的成对测试集,就是调 用图中边的数量

  • 相邻集成:为减少测试的数量,以相邻节点为集合,进行测试。相邻节点:包括所有直接前驱和所有直接后继节点。对于SATM,显然就是除去叶子节点的所有节点的相邻集合

  • 如下图所示,以红色的为中心去数。例如1没有前驱,只有后继结点。这个是个很特殊的。一般来说我们都是考虑16这种,前驱是1,后继9、10、11、12。注意:并不是要一个测试用例吧1、9、10、11、12都测出来,可能是一组测试用例。我们是分组设计测试用例的

2)基于路径的集成

在面向结构的测试中,我们经常采用路径覆盖的方法,在集成测试中,我们也有类似的概念。概念如下:

  • 程序中的源节点是程序开始或重新开始处的语句片段

  • 汇节点是程序执行结束处的语句片断

  • 模块执行路径是以源节点开始,以汇节点结束的一系列语句,中间没有插入汇节点。

  • 消息是一种程序设计语言机制,通过它,一个单元将控 制转移给另一个单元。

  • MM-路径(Model到Model的路径)是穿插出现模块执行路径和消息的序列

  • 如下图所示:1是源节点,因为是模块运行的起点,5也是源节点,因为5是从外面B模块进来的。3也是同理。所以源节点还需考虑从外面模块转入进来的节点

  • 4是汇节点,因为经过了4之后马上就跑到B模块了

  • 模块执行路径是以源节点开始,以汇节点结束的一系列语句,中间没有插入汇节点。

  • 那么上图里面的模块执行路径有:A1-A2-A3-A6、A1-A2-A4、A5-A6、B1-B2、B3-B4、C1-C2-C4-C5、C1-C3-C4-C5。

    • MEP ( A , 1 )=<1,2,3,6>
    • MEP ( A , 2 )=<1,2,4>
    • MEP ( A , 3 )=<5,6>
    • MEP ( B , 1 )=<1,2>
    • MEP ( B , 2 )=<3,4>
    • MEP ( C , 1 )=<1,2,4,5>
    • MEP ( C , 2 )=<1,3,4,5>
  • MM路径就是:一种有向图,其中的节 点表示模块执行路径,边表示消息和单元之间的返回。

  • 上面的MM-路径就表示为如下所示:其中边表示消息的传递

  • 区别DD路径和MM路径
    • DD-路径:模块内的程序执行路径;
    • MM-路径:模块间的模块执行路径序列。
  • 怎么测试呢?基于路径的覆盖,例如上面的图就是3个路径,覆盖了就好!
策略对接口的测试能力对交互功能的测试能力故障分离辨别力
功能分解满意可能不可靠有限单元对好,尤其是有故障单元
调用图满意有限单元对好,尤其是有故障单元
MM路径优秀全部单元优秀,尤其对有故障单元执行路径
  • MM-路径复杂度
    • 圈复杂度的计算:$V(G)=e-n+2p$
    • 其中,e为边数,n为节点数。双向箭头表示2条边

集成测试关注点的话是:我们单元测试完了以后,一个单元测试都通过了。以后单元之和单元之间做集成过程理念。关心的是他们之间的调用关系

三、系统测试(黑盒)

1)回顾

  • 单元测试:白盒(侧重)、详细设计文档;(单元测试也可以做黑盒测试)
  • 集成测试:白盒、概要设计文档
  • 系统测试:从外部特性对软件进行测试,功能测试。是黑盒测试

2)描述功能

我们可以通过系统从输入到输出的行为线索来描述系统。线索有不同的层次,单元级线索被理解为指令执行路径,或DD-路径;集成测试线索是MM-路径,即 模块执行和消息交替序列。那么系统级线索,就是原子系统功能序列。

这样的定义并不令人满意,换个角度,单元测试的线索是模块内的路径执行序列(有意义的最小单 元);集成测试的线索是模块间的路径执行序列(是小于系统级的意义单元);系统级的线索,是 系统输入到输出的路径(是功能的最小单元)。

回归到之前的SATM中的可能线索:数字输入-屏幕输出,密码(PIN)验证。单一事务:存款、取款、查询余额。多个事务:包括两个或多个业务活动。当然,仅对于密码验证而言,还可以细化为插 卡和密码输入2个线索。而密码可以有三次尝试

3)原子系统功能

  • 原子系统功能(ASF):是一种在系统层可 以观察得到的端口输入和输出事件的行动
  • ASF具有事件静止特性,ASF开始于一个端口(系统级端口)输入事件,遍历一个或多个MM路径,以一个端口(系统级端口)输出事件结束。ASF具有事件序列原子化(不愿再细分)特性。 已经是最小了,不能再细分了。
  • 所以,比如卡输入、PIN输入也就不能再细分了
  • 原子系统功能就是为了查找系统的最小单元

4)ASF图

  • 给定通过原子系统功能描述的系统,系统的ASF图是一种有向图,其中的节点表示ASF, 边表示串行流。
  • 源ASF是一种原子系统功能,在系统ASF 图中作为源节点出现。汇ASF也是一种原子系统 功能,在系统ASF图中作为汇节点出现
  • 系统线索在系统的ASF图中,是从源ASF到 汇ASF的路径。

需求规格说明的基本概念:

  • 数据:整数、浮点数、字符串、数组、结构体等;
  • 操作:输入、输出、转换、处理、活动、任务、方 法、服务;
  • 设备:端口设备、系统I/O接口;
  • 事件:发生在端口设备上的系统级输入(或输出), 是操作+数据

建立系统的ASF图,是软件建模的方式之一。换 言之,是建立需求规格的形式化方法之一。有限状态机(FSM)是研究系统功能级线索的有 效手段。换言之,有限状态机恰是我们前面定义 的ASF图。

  • FSM:节点=ASF
  • 边=事件和行动

5)ASF例子

  • 如下图所示,是课本183页面的状态机的图

  • 对于下图里面的,我们这样分析

  • 首先,下图里面的路径,分为三种路径:

    • 第一种是正确输入了的,只有一条
    • 第二种是输入一半取消了的,有4条
    • 第三种是输入错了,只有一条

  • 算算有多少不同的线索(从源到汇的路径)
  • 第1次PIN才输入正确:1条
  • 第2次PIN才输入正确:5条;(因为第一次输错或者取消了,对照上图的这个情况,第一次只有五种可能,第二次只有一种可能,所以一共合起来 $5 \times 1= 5$)
  • 第3次PIN才输入正确:25条;(因为前两次输错了或者取消了,前两次每一次都有五种可能,最后一次一种可能)
  • 不正确的路径:125条(三次都没输入正确或者取消了,$5 \times 5 \times 5$)

那么得出来路径之后,我们就只需要考虑路径的覆盖了!对于PIN的细化状态图,共有6条路径。分别设计测试用例,覆盖这些路径就好。

6)基于用例的测试

用例的层次:

  • 高级用例(非常类似于一个敏捷开发故事)
  • 基本用例
  • 基本扩展用例

7)基于规格说明系统测试的覆盖率

基于状态图的测试方法很有效,但并不是所有的软件系统 都能够方便的得到状态图。而系统功能确是各个系统都十 分明确的线索,下面我们就从功能定义的三个基本构件: 事件、端口和数据,讨论测试的线索。

a)基于事件的线索测试

基于事件的线索测试:从端口的输入事件考虑,有5个覆盖标准:

  • PI1:每个端口输入事件发生。
  • PI2:端口输入事件的常见序列发生。
  • PI3:每个端口输入事件在所有“相关”数据语境中发 生。
  • PI4:对于给定语境,所有“不合适”的输入事件发生。
  • PI5:对于给定语境,所有可能的输入事件发生。

PI1是易于达到的,PI2是基本可行的。而PI3就有可能形成测试爆炸,而PI4和PI5往往是供参考的选项。

从端口的输出事件考虑,可以有两种覆盖指标

  • PO1:每个端口输出事件发生。
  • PO2:每个端口输出事件在每种情况下发生。
  • PO1是基本的要求,PO2不仅要求所有的输出事件, 而且要考虑导致这种输出的所有可能原因,这个要求 往往也是难以完全满足的
b)基于数据的线索测试:
  • 基于端口和事件的测试适合主要以事件驱动的系统, 但并不是所有的系统都是事件驱动系统,例如以数据 库为基础的系统,主要是数据的操作,此时就可以采用基于数据的测试。
  • 覆盖指标:DM1:检查每个关系的基数。DM2:检查每个关系的参与。DM3:检查关系之间的函数依赖关系。 基数指:关系间的一对一、一对多、多对一、多 对多关系

8)系统测试方针

伪结构系统测试

  • 伪结构是系统的行为模型,是系统实际情况的 近似模型。
  • 决策表、状态图、Petri网是系统功能性测试的 常见选择。 运行剖面
  • 齐夫定理(Zipf’s Law)在大多数情况下都成立。 即80%的活动发生在20%的空间里(二八定 理)。
  • 因此,确定各种线索的执行频率,对事件发生频率高的线索执行测试,可以大大提高测试的效率

7)基于风险的测试

把上面的状态路,计算出来每一个状态出来之后,不同路径的概率。然后根据概率选择。

  • 不如大多数人都是输入正确的密码,我就应该多测试输入正确密码后面的分支
  • 运行剖面提供了系统的使用情况,对优化系统测试有意义。
  • 对客户使用情况的了解,是改进系 统设计的重要依据。对于发生概率极小甚至为零 的线索,也许恰恰占用了系统的极大资源
  • 风险=代价 乘以 发生概率
  • 失效代价通过四种风险类别给定:如1代表失效 代价低、3为中间值、10为代价高