Home 软件工程-系统测试
Post
Cancel

软件工程-系统测试

软件工程系列文章三

系统测试的意义、目的及原则

系统测试是为了发现错误而执行程序的过程,成功的测试是发现了至今尚未发现的错误的测试

测试的目的就是希望能以最少的人力和时间发现潜在的各种错误和缺陷。用户应根据开发各阶段的需求、设计等文档或程序的内部结构精心设计测试用例,并利用这些实例来运行程序,以便发现错误的过程

信息系统测试应包括软件测试、硬件测试和网络测试。硬件测试、网络测试可以根据具体的性能指标进行,此处所说的测试更多的是指软件测试

系统测试是保证系统质量和可靠性的关键步骤,是对系统开发过程中的系统分析、系统设计和实施的最后复查。根据测试的概念和目的,在进行信息系统测试时应遵循以下基本原则

  1. 应尽早并不断地进行测试。测试不是在应用系统开发完之后才进行的。由于原始问题的复杂性、开发各阶段的多样性以及参加人员之间的协调等因素,使得在开发的各个阶段都有可能出现错误。因此,测试应贯穿在开发的各个阶段,应尽早纠正错误,消除隐患
  2. 测试工作应该避免由原开发软件的人或小组承担,一方面,开发人员往往不愿否认自己的工作,总认为自己开发的软件没有错误;另一方面,开发人员的错误很难由本人测试出来,很容易根据自己编程的思路来制定测试思路,具有局限性,测试工作应由专门人员来进行,这样会更客观、更有效
  3. 在设计测试方案时,不仅要确定输入数据,而且要根据系统功能确定预期输出结果。将实际输出结果与预期结果相比较就能发现测试对象是否正确
  4. 在设计测试用例时,不仅要设计有效、合理的输入条件,也要包含不合理、失效的输入条件。在测试的时候,人们往往习惯按照合理的、正确的情况进行测试,而忽略了对异常、不合理、意想不到的情况进行测试,而这可能就是隐患
  5. 在测试程序时,不仅要检验程序是否做了该做的事,还要检验程序是否做了不该做的事。多余的工作会带来副作用,影响程序的效率,有时会带来潜在的危害或错误
  6. 严格按照测试计划来进行,避免测试的随意性。测试计划应包括测试内容、进度安排、人员安排、测试环境、测试工具和测试资料等。严格地按照测试计划可以保证进度,使各方面都得以协调进行
  7. 妥善保存测试计划、测试用例,作为软件文档地组成部分,为维护提供方便
  8. 测试例子都是精心设计出来的,可以为重新测试或追加测试提供方便。当纠正错误、系统功能扩充后,都需要重新开始测试,而这些工作的重复性很高,可以利用以前的测试用例或在其基础上修改,然后进行测试

系统测试阶段的测试目标来自于需求分析阶段

传统软件的测试策略

有效的软件测试实际上分为 4 步进行,即单元测试、集成测试、确认测试和系统测试

(一) 单元测试

单元测试也称为模块测试,在模块编写完成且无编译错误后就可以进行。单元测试侧重于模块中的内部处理逻辑和数据结构。如果选用机器测试,一般用白盒测试法。这类测试可以对多个模块同时进行

(1) 单元测试的测试内容

单元测试主要检查模块的以下 5 个特征

  1. 模块接口。模块的接口保证了测试模块的数据流可以正确地流入、流出。在测试中应检查以下要点:
    1. 测试模块的输入参数和形式参数在个数、属性、单位上是否一致
    2. 调用其他模块时,所给出的实际参数和被调用模块的形式参数在个数、属性、单位上是否一致
    3. 调用标准函数时,所用的参数在属性、数目和顺序上是否正确
    4. 全局变量在各模块中的定义和用法是否一致
    5. 输入是否仅改变了形式参数
    6. 开/关的语句是否正确
    7. 规定的 I/O 格式是否与输入/输出语句一致
    8. 在使用文件之前是否已经打开文件或使用文件之后是否已经关闭文件
  2. 局部数据结构。在单元测试中,局部数据结构出错是比较常见的错误,在测试时应重点考虑以下因素
    1. 变量的说明是否合适
    2. 是否使用了尚未赋值或尚未初始化的变量
    3. 变量的初始值或默认值是否正确
    4. 变量名是否有错 (例如拼写错)
  3. 重要的执行路径。在单元测试中,对路径的测试是最基本的任务。由于不能进行穷举测试,需要精心设计测试例子来发现是否有计算、比较或控制流等方面的错误
    1. 计算方面的错误。算术运算的优先次序不正确或理解错误;精度不够;运算对象的类型彼此不相容;算法错;表达式的符号表示不正确
    2. 比较和控制流的错误。本应相等的量由于精度造成不相等;不同类型进行比较;逻辑运算符不正确或优先次序错误;循环终止不正确 (如多循环一次或少循环一次) 、死循环;不恰当地修改循环变量;当遇到分支循环时出口错误等
  4. 出错处理。好的设计应该能预测到出错的条件并且有对出错处理的路径。虽然计算机可以显示出错信息的内容,但仍需要程序员对出错进行处理,保证其逻辑的正确性,以便于用户维护
  5. 边界条件。边界条件的测试是单元测试的最后工作,也是非常重要的工作。软件容易在边界出现错误

(2) 单元测试过程

由于模块不是独立运行的程序,各模块之间存在调用与被调用的关系。在对每个模块进行测试时,需要开发两种模块

  • 驱动模块。相当于一个主程序,接受测试例子的数据,将这些数据送到测试模块,输出测试结果
  • 桩模块 (也称为存根模块) 。桩模块用来代替测试模块中所调用的子模块,其内部可进行少量的数据处理,目的是为了检验入口,输出调用和返回的信息

单元测试环境

提高模块的内聚度可以简化单元测试。如果每个模块只完成一种功能,对于具体模块来讲,所需的测试方案数据会显著减少,而且更容易发现和预测模块中的错误

(二)集成测试

集成测试就是把模块按系统设计说明书的要求组合起来进行测试。即使所有的模块都通过了测试,在集成之后,仍然可能出现问题

通常,集成测试有两种方法:一种是非增量集成,分别测试各个模块,再把这些模块组合起来整体测试;另一种是增量集成,即以小增量的方式逐步进行构造和测试

下面是一些增量集成策略

(1) 自顶向下集成测试

自顶向下集成测试是一种构造软件体系结构的增量方法。模型的集成顺序为从主控模块 (主程序) 开始,沿着控制层次逐步向下,以深度优先或广度优先的方式将从属于 (或间接从属于) 主控模块的模块集成到结构中

深度优先集成是首先集成位于程序结构中主控路径上的所有构件,也可以根据特定应用系统的特征进行选择

自顶向下集成

  1. 主控模块用作测试驱动模块,用这些从属于主控模块的所有模块代替桩模块
  2. 依赖所选择的集成方法 (即深度优先或广度优先) ,每次用实际模块替换一个从属桩模块
  3. 在集成每个模块后都进行测试
  4. 在完成每个测试集之后,用实际模块替换另一个桩模块
  5. 可以执行回归测试,以确保没有引入新的错误
  6. 回到第 2 步继续执行此过程,直到完成了整个程序结构的构造

不用编写驱动模块,需要编写桩模块

(2) 自底向上集成测试

自底向上集成测试就是从原子模块 (程序结构的最底层构件) 开始进行构造和测试。由于构件是自底向上集成的,在处理时所需要的从属于给定层次的模块总是存在的,因此,没有必要使用桩模块。自底向上集成策略可以利用以下步骤来实现

自底向上集成

  1. 连接底层构件以构成完成特定子功能的簇
  2. 编写驱动模块 (测试的控制程序) 以协调测试用例的输入和输出
  3. 测试簇
  4. 去掉驱动程序,沿着程序结构向上逐步连接簇

不需要编写桩模块,需要编写驱动模块

(3) 回归测试

每当加入一个新模块作为集成测试的一部分时,软件发生变更,建立了新的数据流路径,可能出现新的 I/O,以及调用新的控制逻辑。这些变更可能会使原来可以正常工作的功能产生问题。在集成测试策略的环境下,回归测试是重新执行已测试过的某些子集,以确保变更没有传播不期望的副作用

回归测试有助于保证变更不引入无意识行为或额外的错误。回归测试可以手工进行,方法是重新执行所有测试用例的子集,或者利用捕捉/回放工具自动执行。捕捉/回放工具使软件工程师能够为后续的回放与比较捕捉测试用例和测试结果。回归测试要执行的测试子集包含以下 3 种测试用例

  • 能够测试软件所有功能的具有代表性的测试样本
  • 额外测试,侧重于可能会受变更影响的软件功能
  • 侧重于已发生变更的软件构件测试

随着集成测试的进行,回归测试的数量可能变得相当庞大,因此,应将回归测试用例设计成只包括设计每个主要程序功能的一个或多个错误类的测试。一旦发生变更,对每个软件功能重新执行所有的测试是不切实际的,而且效率很低

(4) 冒烟测试

当开发软件产品时,冒烟测试是一种常见的集成测试方法,是时间关键项目的决定性机制,它让软件团队频繁地对项目进行评估

测试方法

在软件测试过程中,应该为定义软件测试模板,即将特定的测试方法和测试用例设计放在一系列的测试步骤中

软件测试方法分为静态测试和动态测试

  1. 静态测试。静态测试是指被测试程序不在机器上运行,而是采用人工检测和计算机辅助静态分析的手段对程序进行检测
    1. 人工检测。人工检测不依靠计算机而是依靠人工审查程序或评审软件,包括代码检查、静态结构分析和代码质量度量等
    2. 计算机辅助静态分析。利用静态分析工具对被测试程序进行特性分析,从程序中提取一些信息,以便检查程序逻辑的各种缺陷和可疑的程序构造
  2. 动态测试。动态测试是指通过运行程序发现错误。在对软件产品进行动态测试时可以采用黑盒测试法和白盒测试法

测试用例由测试输入数据和与之对应的预期输出结果组成。在设计测试用例时,应当包括合理的输入条件和不合理的输入条件

(一) 黑盒测试

黑盒测试也称为功能测试,在完全不考虑软件的内部结构和特性的情况下,测试软件的外部特性

常见的黑盒测试技术有等价类划分、边界值分析、错误推测和因果图等

(1) 等价类划分

等价类划分将程序的输入域划分为若干等价类,然后从每个等价类中选取 一个代表性数据作为测试用例。每一类的代表性数据在测试中的作用等价于这一类中的其他值,这样就可以用少量代表性的测试用例取得较好的测试效果。等价类型划分有两种不同的情况:有效等价类和无效等价类。在设计测试用例时,要同时考虑这两种等价类

(2) 边界值分析

输入的边界比中间更加容易发生错误,因此用边界值分析来补充等价类划分的测试用例设计技术。边界值划分选择等价类边界的测试用例,即注重于输入条件边界,又适用于输出域测试用例

(3) 错误推测

错误推测是基于经验和直觉推测程序中所有可能存在的各种错误,从而有针对性地设计测试用例的方法。其基本思想是列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例

(4) 因果图

因果图法是从自然语言描述的程序规格说明中找出因 (输入条件) 和果 (输出或程序状态的改变) ,通过因果图转换为判定表

(二) 白盒测试

白盒测试也称为结构测试,根据程序的内部结构和逻辑来设计测试用例,对程序的路径和过程进行测试,检查是否满足设计的需要

白盒测试常用的技术是逻辑覆盖、循环覆盖和基本路径测试

白盒测试的原则如下:

  1. 程序模块中的所有独立路径至少执行一次
  2. 在所有的逻辑判定中,取 “真” 和取 “假” 的两种情况至少都能执行一次
  3. 每个循环都应在边界条件和一般条件下各执行一次
  4. 测试程序内部数据结构的有效性等

(1) 逻辑覆盖

逻辑覆盖考察用测试数据运行被测程序时对程序逻辑的覆盖程度,主要的逻辑覆盖标准有语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖 6 种

  1. 语句覆盖。语句覆盖是指选择足够的测试数据,使被测试程序中的每条语句至少执行一次。语句覆盖对程序执行逻辑的覆盖很低,因此一般认为它是很弱的逻辑覆盖
  2. 判定覆盖。判定覆盖是指设计足够的测试用例,使得被测程序中的每个判定表达式至少获得一次 “真” 值和 “假” 值,或者说是程序中的每一个取 “真” 分支和取 “假” 分支至少都通过一次,因此判定覆盖也称为分支覆盖。判定覆盖要比语句覆盖更强一些
  3. 条件覆盖。条件覆盖是指构造一组测试用例,使得每一判定语句中每个逻辑条件的各种可能的值至少满足一次
  4. 判定/条件覆盖。判定/条件覆盖是指设计足够的测试用例,使得判定中每个条件的所有可能取值 (真/假) 至少出现一次,并使每个判定本身的判定结果 (真/假) 也至少出现一次
  5. 条件组合覆盖。条件组合覆盖是指设计足够的测试用例,使得每个判定中条件的各种可能值的组合都至少出现一次。满足条件组合覆盖的测试用例是一定满足判定覆盖、条件覆盖和判定/条件覆盖的
  6. 路径覆盖。路径覆盖是指覆盖被测试程序中所有可能的路径

(2) 循环覆盖

执行足够的测试用例,使得循环中的每个条件都得到验证

(3) 基本路径测试

基本路径测试法是在程序控制流图的基础上通过分析控制流图的环路复杂性,导出基本可执行路径集合,从而设计测试用例

调试

调试发生在测试之后,其任务是根据测试时所发现的错误找出原因和具体的位置,进行改正

常用的调试方法有以下几种

(1) 试探法

调试人员分析错误的症状,猜测问题所在的位置,利用在程序中设置输出语句,分析寄存器、存储器的内容等手段获得错误的线索,一步步地试探和分析错误的所在

(2) 回溯法

调试人员从发现错误症状的位置开始,人工沿着程序的控制流程往回跟踪代码,直到找出错误根源为止

(3) 对分查找法

这种方法主要用来缩小错误的范围,如果已经知道程序中的变量在若干位置的正确取值,可以在这些位置上给这些变量以正确值,观察程序运行的输出结果,如果没有发现问题,则说明从赋予变量一个正确值开始到输出结果之间的程序没有错误,问题可能在除此之外的程序中。否则错误就在所考察的这部分程序中,对含有错误的程序段再使用这种方法,直到把故障范围缩小到比较容易诊断为止

(4) 归纳法

归纳法就是从测试所暴露的问题出发,收集所有正确或不正确的数据,分析它们之间的关系,提出假想的错误原因,用这些数据来证明或反驳,从而查出错误所在

(5) 演绎法

演绎法根据测试结果,列出所有可能的错误原因;分析已有的数据,排除不可能和彼此矛盾的原因;对其余的原因,选择可能性最大的,利用已有的数据完善该假设,使假设更具体;用假设来解释所有的原始测试结果,如果能解释这一切,则假设得以证实,也就找出错误

This post is licensed under CC BY 4.0 by the author.

软件工程-需求分析与系统设计

软件工程-系统维护概述