第五章软件测试 复习要求 1.了解软件测试的目的和原则。 2.了解软件错误的分类 3.了解软件测试的过程和策略。 4!.了解软件测试用例设计的方法,掌握逻辑覆盖、基本路径测试、因果图等测试用例设 计方法 5.了解程序静态测试的方法。 6.了解程序调试的概念。 7.掌握软件测试中的可靠性分析方法 内容提要 1.软件测试基础 (1)什么是软件测试 软件测试是为了发现错误而执行程序的过程。或者说,软件测试是根据软件开发各阶段 的规格说明和程序的内部结构而精心设计一批测试用例(即输入数据及其预期的输出结果) 并利用这些测试用例去运行程序,以发现程序错误的过程 软件测试在软件生存期中横跨两个阶段:通常在编写出每一个模块之后就对它做必要的 测试(称为单元测试)。模块的编写者与测试者是同一个人。编码与单元测试属于软件生存期 中的同一个阶段。在这个阶段结束之后,对软件系统还要进行各种综合测试,这是软件生存 期的另一个独立的阶段,即测试阶段,通常由专门的测试人员承担这项工作。 (2)软件测试的目的和原则 Grenford J Myers就软件测试目的提出以下观点: 测试是程序的执行过程,目的在于发现错误 一个好的测试用例在于能发现至今未发现的错误 一个成功的测试是发现了至今未发现的错误的测试 设计测试的目标是想以最少的时间和人力系统地找出软件中潜在的各种错误和缺陷。如 果我们成功地实施了测试,就能够发现软件中的错误。测试的附带收获是,它能够证明软件 的功能和性能与需求说明相符合。此外,实施测试收集到的测试结果数据为可靠性分析提供 了依据。 测试不能表明软件中不存在错误,它只能说明软件中存在错误 软件测试的原则: ①应当把“尽早地和不断地进行软件测试”作为软件开发者的座右铭 不应把软件测试仅仅看作是软件开发的一个独立阶段,而应当把它贯穿到软件开发的各 个阶段中。坚持在软件开发的各个阶段的技术评审,这样才能在开发过程中尽早发现和预防 错误,把出现的错误克服在早期,杜绝某些发生错误的隐患 ②测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成
1 第五章 软件测试 一、复习要求 1. 了解软件测试的目的和原则。 2. 了解软件错误的分类。 3. 了解软件测试的过程和策略。 4. 了解软件测试用例设计的方法,掌握逻辑覆盖、基本路径测试、因果图等测试用例设 计方法。 5. 了解程序静态测试的方法。 6. 了解程序调试的概念。 7. 掌握软件测试中的可靠性分析方法 二、内容提要 1. 软件测试基础 (1) 什么是软件测试 软件测试是为了发现错误而执行程序的过程。或者说,软件测试是根据软件开发各阶段 的规格说明和程序的内部结构而精心设计一批测试用例(即输入数据及其预期的输出结果), 并利用这些测试用例去运行程序,以发现程序错误的过程。 软件测试在软件生存期中横跨两个阶段:通常在编写出每一个模块之后就对它做必要的 测试(称为单元测试)。模块的编写者与测试者是同一个人。编码与单元测试属于软件生存期 中的同一个阶段。在这个阶段结束之后,对软件系统还要进行各种综合测试,这是软件生存 期的另一个独立的阶段,即测试阶段,通常由专门的测试人员承担这项工作。 (2) 软件测试的目的和原则 Grenford J.Myers 就软件测试目的提出以下观点: ▪ 测试是程序的执行过程,目的在于发现错误; ▪ 一个好的测试用例在于能发现至今未发现的错误; ▪ 一个成功的测试是发现了至今未发现的错误的测试。 设计测试的目标是想以最少的时间和人力系统地找出软件中潜在的各种错误和缺陷。如 果我们成功地实施了测试,就能够发现软件中的错误。测试的附带收获是,它能够证明软件 的功能和性能与需求说明相符合。此外,实施测试收集到的测试结果数据为可靠性分析提供 了依据。 测试不能表明软件中不存在错误,它只能说明软件中存在错误。 软件测试的原则: ① 应当把“尽早地和不断地进行软件测试”作为软件开发者的座右铭。 不应把软件测试仅仅看作是软件开发的一个独立阶段,而应当把它贯穿到软件开发的各 个阶段中。坚持在软件开发的各个阶段的技术评审,这样才能在开发过程中尽早发现和预防 错误,把出现的错误克服在早期,杜绝某些发生错误的隐患。 ② 测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成
测试以前应当根据测试的要求选择测试用例( Test case),用来检验程序员编制的程序, 因此不但需要测试的输入数据,而且需要针对这些输入数据的预期输出结果 ③程序员应避免检查自己的程序。 程序员应尽可能避免测试自己编写的程序,程序开发小组也应尽可能避免测试本小组开 发的程序。如果条件允许,最好建立独立的软件测试小组或测试机构。这点不能与程序的调 试( debuging)相混淆。调试由程序员自己来做可能更有效。 ④在设计测试用例时,应当包括合理的输入条件和不合理的输入条件。 合理的输入条件是指能验证程序正确的输入条件,不合理的输入条件是指异常的,临界 的,可能引起问题异变的输入条件。软件系统处理非法命令的能力必须在测试时受到检验。 用不合理的输入条件测试程序时,往往比用合理的输入条件进行测试能发现更多的错误 ⑤充分注意测试中的群集现象 在被测程序段中,若发现错误数目多,则残存错误数目也比较多。这种错误群集性现象 已为许多程序的测试实践所证实。根据这个规律,应当对错误群集的程序段进行重点测试, 以提高测试投资的效益 ⑥严格执行测试计划,排除测试的随意性 测试之前应仔细考虑测试的项目,对每一项测试做出周密的计划,包括被测程序的功能 输入和输出、测试内容、进度安排、资源要求、测试用例的选择、测试的控制方式和过程等 还要包括系统的组装方式、跟踪规程、调试规程,回归测试的规定,以及评价标准等。对于 测试计划,要明确规定,不要随意解释 ⑦应当对每一个测试结果做全面检查。 有些错误的征兆在输出实测结果时已经明显地出现了,但是如果不仔细地全面地检査测 试结果,就会使这些错误被遗漏掉。所以必须对预期的输出结果明确定义,对实测的结果仔 细分析检査,抓住征侯,暴露错误。 ⑧妥善保存测试计划,测试用例,出错统计和最终分析报告,为维护提供方便。 (3)确认和验证的关系 确认(Ⅷ alidation)是一系列的活动和过程,其目的是想证实在一个给定的外部环境中软 件的逻辑正确性。它包括需求規格说明的确认和程序的确认,而程序的确认又分为静态确认 与动态确认。静态确认一般不在计算机上实际执行程序,而是通过人工分析或者程序正确性 证明来确认程序的正确性:动态确认主要通过动态分析和程序测试来检査程序的执行状态, 以确认程序是否有问题。 验证( Verification),则试图证明在软件生存期各个阶段,以及阶段间的逻辑协调性、完 备性和正确性 确认与验证工作都属于软件测试。在对需求理解与表达的正确性、设计与表达的正确性、 实现的正确性以及运行的正确性的验证中,任何一个环节上发生了问题都可能在软件测试中 表现出来。 (4)测试信息流 测试信息流如图5.1所示。测试过程需要三类输入: 软件配置:包括软件需求规格说明、软件设计规格说明、源代码等 测试配置:包括测试计划、测试用例、测试驱动程序等; 测试工具:测试工具为测试的实施提供某种服务。例如,测试数据自动生成程序、 静态分析程序、动态分析程序、测试结果分析程序、以及驱动测试的工作台等。 测试之后,用实测结果与预期结果进行比较。如果发现出错的数据,就要进行调试。对 已经发现的错误进行错误定位和确定出错性质,并改正这些错误,同时修改相关的文档。修 正后的文档一般都要经过再次测试,直到通过测试为止
2 测试以前应当根据测试的要求选择测试用例(Test case),用来检验程序员编制的程序, 因此不但需要测试的输入数据,而且需要针对这些输入数据的预期输出结果。 ③ 程序员应避免检查自己的程序。 程序员应尽可能避免测试自己编写的程序,程序开发小组也应尽可能避免测试本小组开 发的程序。如果条件允许,最好建立独立的软件测试小组或测试机构。这点不能与程序的调 试(debuging)相混淆。调试由程序员自己来做可能更有效。 ④ 在设计测试用例时,应当包括合理的输入条件和不合理的输入条件。 合理的输入条件是指能验证程序正确的输入条件,不合理的输入条件是指异常的,临界 的,可能引起问题异变的输入条件。软件系统处理非法命令的能力必须在测试时受到检验。 用不合理的输入条件测试程序时,往往比用合理的输入条件进行测试能发现更多的错误。 ⑤ 充分注意测试中的群集现象。 在被测程序段中,若发现错误数目多,则残存错误数目也比较多。这种错误群集性现象, 已为许多程序的测试实践所证实。根据这个规律,应当对错误群集的程序段进行重点测试, 以提高测试投资的效益。 ⑥ 严格执行测试计划,排除测试的随意性。 测试之前应仔细考虑测试的项目,对每一项测试做出周密的计划,包括被测程序的功能、 输入和输出、测试内容、进度安排、资源要求、测试用例的选择、测试的控制方式和过程等, 还要包括系统的组装方式、跟踪规程、调试规程,回归测试的规定,以及评价标准等。对于 测试计划,要明确规定,不要随意解释。 ⑦ 应当对每一个测试结果做全面检查。 有些错误的征兆在输出实测结果时已经明显地出现了,但是如果不仔细地全面地检查测 试结果,就会使这些错误被遗漏掉。所以必须对预期的输出结果明确定义,对实测的结果仔 细分析检查,抓住征侯,暴露错误。 ⑧ 妥善保存测试计划,测试用例,出错统计和最终分析报告,为维护提供方便。 (3) 确认和验证的关系 确认(Validation)是一系列的活动和过程,其目的是想证实在一个给定的外部环境中软 件的逻辑正确性。它包括需求规格说明的确认和程序的确认,而程序的确认又分为静态确认 与动态确认。静态确认一般不在计算机上实际执行程序,而是通过人工分析或者程序正确性 证明来确认程序的正确性; 动态确认主要通过动态分析和程序测试来检查程序的执行状态, 以确认程序是否有问题。 验证(Verification),则试图证明在软件生存期各个阶段,以及阶段间的逻辑协调性、完 备性和正确性。 确认与验证工作都属于软件测试。在对需求理解与表达的正确性、设计与表达的正确性、 实现的正确性以及运行的正确性的验证中,任何一个环节上发生了问题都可能在软件测试中 表现出来。 (4) 测试信息流 测试信息流如图 5.1 所示。测试过程需要三类输入: ▪ 软件配置:包括软件需求规格说明、软件设计规格说明、源代码等; ▪ 测试配置:包括测试计划、测试用例、测试驱动程序等; ▪ 测试工具:测试工具为测试的实施提供某种服务。例如,测试数据自动生成程序、 静态分析程序、动态分析程序、测试结果分析程序、以及驱动测试的工作台等。 测试之后,用实测结果与预期结果进行比较。如果发现出错的数据,就要进行调试。对 已经发现的错误进行错误定位和确定出错性质,并改正这些错误,同时修改相关的文档。修 正后的文档一般都要经过再次测试,直到通过测试为止
通过收集和分析测试结果数据,对软件建立可靠性模型。 错 排错 改正的软件 测试 软件配置 测试配置 果 测试工具 分析 预测的可靠性 图5.1测试信息流 如果测试发现不了错误,那么可以肯定,测试配置考虑得不够细致充分,错误仍然潜伏 在软件中。这些错误最终不得不由用户在使用中发现,并在维护时由开发者去改正。但那时 改正错误的费用将比在开发阶段改正错误的费用要高出40倍到60倍。 (5)测试与软件开发各阶段的关系 软件开发过程是一个自顶向下,逐步细化的过程,而测试过程则是依相反的顺序安排的 自底向上,逐步集成的过程。低一级测试为上一级测试准备条件。参看图52,首先对每一个 程序模块进行单元测试,消除程序模块内部在逻辑上和功能上的错误和缺陷。再对照软件设 计进行集成测试,检测和排除子系统(或系统)结构上的错误。随后再对照需求,进行确认 测试。最后从系统全体出发,运行系统,看是否满足要求 需求分析 设计 集成测试一单元测试」一 球分析L概要设计。详细设 说明书」L说明书」ˉ说明书」ˉ代码」测试」测试 则试 图52软件测试与软件开发过程的关系 2.程序错误分类 由于人们对错误有不同的理解和认识,所以目前还没有一个统一的错误分类方法。错误 难于分类的原因,一方面是由于一个错误有许多征兆,因而它可以被归入不同的类。另一方 面是因为把一个给定的错误归于哪一类,还与错误的来源和程序员的心理状态有关 (1)按错误的影响和后果分类 ■较小错误:只对系统输出有一些非实质性影响。如,输出的数据格式不合要求等 中等错误:对系统的运行有局部影响。如输出的某些数据有错误或出现冗余 ■较严重错误:系统的行为因错误的干扰而出现明显不合情理的现象。比如开出了000
3 通过收集和分析测试结果数据,对软件建立可靠性模型。 图 5.1 测试信息流 如果测试发现不了错误,那么可以肯定,测试配置考虑得不够细致充分,错误仍然潜伏 在软件中。这些错误最终不得不由用户在使用中发现,并在维护时由开发者去改正。但那时 改正错误的费用将比在开发阶段改正错误的费用要高出 40 倍到 60 倍。 (5) 测试与软件开发各阶段的关系 软件开发过程是一个自顶向下,逐步细化的过程,而测试过程则是依相反的顺序安排的 自底向上,逐步集成的过程。低一级测试为上一级测试准备条件。参看图 5.2,首先对每一个 程序模块进行单元测试,消除程序模块内部在逻辑上和功能上的错误和缺陷。再对照软件设 计进行集成测试,检测和排除子系统(或系统)结构上的错误。随后再对照需求,进行确认 测试。最后从系统全体出发,运行系统,看是否满足要求。 图 5.2 软件测试与软件开发过程的关系 2. 程序错误分类 由于人们对错误有不同的理解和认识,所以目前还没有一个统一的错误分类方法。错误 难于分类的原因,一方面是由于一个错误有许多征兆,因而它可以被归入不同的类。另一方 面是因为把一个给定的错误归于哪一类,还与错误的来源和程序员的心理状态有关。 (1) 按错误的影响和后果分类 ▪ 较小错误:只对系统输出有一些非实质性影响。如,输出的数据格式不合要求等。 ▪ 中等错误:对系统的运行有局部影响。如输出的某些数据有错误或出现冗余。 ▪ 较严重错误:系统的行为因错误的干扰而出现明显不合情理的现象。比如开出了0.00
元的支票,系统的输出完全不可信赖 ■严重错误:系统运行不可跟踪,一时不能掌握其规律,时好时坏 ■非常严重的错误:系统运行中突然停机,其原因不明,无法软启动。 ■最严重的错误:系统运行导致环境破坏,或是造成事故,引起生命、财产的损失。 (2)按错误的性质和范围分类 B Beizer从软件测试观点出发,把软件错误分为5类 ①功能错误 ■规格说明错误:规格说明可能不完全,有二义性或自身矛盾 ■功能错误:程序实现的功能与用户要求的不一致。这常常是由于规格说明中包含错 误的功能、多余的功能或遗漏的功能所致 测试错误:软件测试的设计与实施发生错误。软件测试自身也可能发生错误。 测试标准引起的错误:对软件测试的标准要选择适当,若测试标准太复杂,则导致 测试过程出错的可能就大 ②系统错误 ■外部接口错误:外部接口指如终端、打印机、通信线路等系统与外部环境通信的手 段。所有外部接口之间,人与机器之间的通信都使用形式的或非形式的专门协议。如果协议 有错,或太复杂,难以理解,致使在使用中岀错。此外还包括对输入/输出格式错误理解 对输入数据不合理的容错等等。 内部接口错误:内部接口指程序之间的联系。它所发生的错误与程序内实现的细节 有关。例如,设计协议错、输入/输出格式错、数据保护不可靠、子程序访问错等。 ■硬件结构错误:这类错误在于不能正确地理解硬件如何工作。例如,忽视或错误地 理解分页机构、地址生成、通道容量、I/O指令、中断处理、设备初始化和启动等而导致的 出错。 操作系统错误:这类错误主要是由于不了解操作系统的工作机制而导致出错。。当然 操作系统本身也有错误,但是一般用户很难发现这种错误 ■软件结构错误:由于软件结构不合理或不清晰而引起的错误。这种错误通常与系统 的负载有关,而且往往在系统满载时才出现。这是最难发现的一类错误。例如,错误地设置 局部参数或全局参数:错误地假定寄存器与存储器单元初始化了:错误地假定不会发生中断 而导致不能封锁或开中断:错误地假定程序可以绕过数据的内部锁而导致不能关闭或打开内 部锁:错误地假定被调用子程序常驻内存或非常驻内存等等,都将导致软件出错 控制与顺序错误:这类错误包括:忽视了时间因素而破坏了事件的顺序:猜测事件 出现在指定的序列中;等待一个不可能发生的条件:漏掉先决条件;规定错误的优先级或程 序状态:漏掉处理步骤;存在不正确的处理步骤或多余的处理步骤等。 ■资源管理错误:这类错误是由于不正确地使用资源而产生的。例如,使用未经获准 的资源:使用后未释放资源;资源死锁:把资源链接在错误的队列中等等。 ③加工错误 算术与操作错误:指在算术运算、函数求值和一般操作过程中发生的错误。包括 数据类型转换错:除法溢出:错误地使用关系比较符:用整数与浮点数做比较等 ■初始化错误:典型的错误有:忘记初始化工作区,忘记初始化寄存器和数据区;错 误地对循环控制变量赋初值:用不正确的格式,数据或类型进行初始化等等 ■控制和次序错误:这类错误与系统级同名错误类似,但它是局部错误。包括:遗漏 路径;不可达到的代码;不符合语法的循环嵌套:循环返回和终止的条件不正确:漏掉处理 步骤或处理步骤有错等 ·静态逻辑错误:这类错误主要包括:不正确地使用CASE语句;在表达式中使用不
4 元的支票,系统的输出完全不可信赖。 ▪ 严重错误:系统运行不可跟踪,一时不能掌握其规律,时好时坏。 ▪ 非常严重的错误:系统运行中突然停机,其原因不明,无法软启动。 ▪ 最严重的错误:系统运行导致环境破坏,或是造成事故,引起生命、财产的损失。 (2) 按错误的性质和范围分类 B.Beizer 从软件测试观点出发,把软件错误分为 5 类。 ① 功能错误 ▪ 规格说明错误:规格说明可能不完全,有二义性或自身矛盾。 ▪ 功能错误:程序实现的功能与用户要求的不一致。这常常是由于规格说明中包含错 误的功能、多余的功能或遗漏的功能所致。 ▪ 测试错误:软件测试的设计与实施发生错误。软件测试自身也可能发生错误。 ▪ 测试标准引起的错误:对软件测试的标准要选择适当,若测试标准太复杂,则导致 测试过程出错的可能就大。 ② 系统错误 ▪ 外部接口错误:外部接口指如终端、打印机、通信线路等系统与外部环境通信的手 段。所有外部接口之间,人与机器之间的通信都使用形式的或非形式的专门协议。如果协议 有错,或太复杂,难以理解,致使在使用中出错。此外还包括对输入/输出格式错误理解, 对输入数据不合理的容错等等。 ▪ 内部接口错误:内部接口指程序之间的联系。它所发生的错误与程序内实现的细节 有关。例如,设计协议错、输入/输出格式错、数据保护不可靠、子程序访问错等。 ▪ 硬件结构错误:这类错误在于不能正确地理解硬件如何工作。例如,忽视或错误地 理解分页机构、地址生成、通道容量、I/O 指令、中断处理、设备初始化和启动等而导致的 出错。 ▪ 操作系统错误:这类错误主要是由于不了解操作系统的工作机制而导致出错。。当然, 操作系统本身也有错误,但是一般用户很难发现这种错误。 ▪ 软件结构错误:由于软件结构不合理或不清晰而引起的错误。这种错误通常与系统 的负载有关,而且往往在系统满载时才出现。这是最难发现的一类错误。例如,错误地设置 局部参数或全局参数;错误地假定寄存器与存储器单元初始化了;错误地假定不会发生中断 而导致不能封锁或开中断;错误地假定程序可以绕过数据的内部锁而导致不能关闭或打开内 部锁;错误地假定被调用子程序常驻内存或非常驻内存等等,都将导致软件出错。 ▪ 控制与顺序错误:这类错误包括:忽视了时间因素而破坏了事件的顺序;猜测事件 出现在指定的序列中;等待一个不可能发生的条件;漏掉先决条件;规定错误的优先级或程 序状态;漏掉处理步骤;存在不正确的处理步骤或多余的处理步骤等。 ▪ 资源管理错误:这类错误是由于不正确地使用资源而产生的。例如,使用未经获准 的资源;使用后未释放资源;资源死锁;把资源链接在错误的队列中等等。 ③ 加工错误 ▪ 算术与操作错误:指在算术运算、函数求值和一般操作过程中发生的错误。包括: 数据类型转换错;除法溢出;错误地使用关系比较符;用整数与浮点数做比较等。 ▪ 初始化错误:典型的错误有:忘记初始化工作区,忘记初始化寄存器和数据区;错 误地对循环控制变量赋初值;用不正确的格式,数据或类型进行初始化等等。 ▪ 控制和次序错误:这类错误与系统级同名错误类似,但它是局部错误。包括:遗漏 路径;不可达到的代码;不符合语法的循环嵌套;循环返回和终止的条件不正确;漏掉处理 步骤或处理步骤有错等。 ▪ 静态逻辑错误:这类错误主要包括:不正确地使用 CASE 语句;在表达式中使用不
正确的否定(例如用“>”代替“<”的否定):对情况不适当地分解与组合:混淆“或”与 异或”等 ④数据错误 动态数据错误:动态数据是在程序执行过程中暂时存在的数据。各种不同类型的动 态数据在程序执行期间将共享一个共同的存储区域,若程序启动时对这个区域未初始化,就 会导致数据出错。由于动态数据被破坏的位置可能与出错的位置在距离上相差很远,因此要 发现这类错误比较困难 静态数据错误:静态数据在内容和格式上都是固定的。它们直接或间接地出现在程 序或数据库中。由编译程序或其它专门程序对它们做预处理。这是在程序执行前防止静态错 误的好办法,但预处理也会出错。 数据内容错误:数据内容是指存储于存储单元或数据结构中的位串、字符串或数字。 数据内容本身没有特定的含义,除非通过硬件或软件给予解释。数据内容错误就是由于内容 被破坏或被错误地解释而造成的错误。 数据结构错误:数据结构是指数据元素的大小和组织形式。在同一存储区域中可以 定义不同的数据结构。数据结构错误主要包括结构说明错误及把一个数据结构误当做另一类 数据结构使用的错误。这是更危险的错误 ■数据属性错误:数据属性是指数据内容的含义或语义。例如,整数、字符串、子程 序等等。数据属性错误主要包括:对数据属性不正确地解释,比如错把整数当实数,允许不 同类型数据混合运算而导致的错误等 ⑤代码错误 主要包括:语法错误;打字错误;对语句或指令不正确理解所产生的错误。 (3)按软件生存期阶段分类 Good enough- Gerhart分类方法把软件的逻辑错误按生存期不同阶段分为4类。 ①问题定义(需求分析)错误 它们是在软件定义阶段,分析员研究用户的要求后所编写的文档中出现的错误。换句话 说,这类错误是由于问题定义不满足用户的要求而导致的错误。 ②规格说明错误 这类错误是指规格说明与问题定义不一致所产生的错误。它们又可以细分成: 不一致性错误:规格说明中功能说明与问题定义发生矛盾。 冗余性错误:规格说明中某些功能说明与问题定义相比是多余的 ■不完整性错误:规格说明中缺少某些必要的功能说明 不可行错误:规格说明中有些功能要求是不可行的 不可测试错误:有些功能的测试要求是不现实的。 ③设计错误 这是在设计阶段产生的错误,它使系统的设计与需求规格说明中的功能说明不相符。它 们又可以细分为: 设计不完全错误:某些功能没有被设计,或设计得不完全。 算法错误:算法选择不合适。主要表现为算法的基本功能不满足功能要求、算法不 可行或者算法的效率不符合要求 ·模块接口错误:模块结构不合理;模块与外部数据库的界面不一致,模块之间的界 面不一致。 ■控制逻辑错误:控制流程与规格说明不一致;控制结构不合理 ■数据结构错误:数据设计不合理;与算法不匹配:;数据结构不满足规格说明要求 ④编码错误
5 正确的否定(例如用“>”代替“<”的否定);对情况不适当地分解与组合;混淆“或”与 “异或”等。 ④ 数据错误 ▪ 动态数据错误:动态数据是在程序执行过程中暂时存在的数据。各种不同类型的动 态数据在程序执行期间将共享一个共同的存储区域,若程序启动时对这个区域未初始化,就 会导致数据出错。由于动态数据被破坏的位置可能与出错的位置在距离上相差很远,因此要 发现这类错误比较困难。 ▪ 静态数据错误:静态数据在内容和格式上都是固定的。它们直接或间接地出现在程 序或数据库中。由编译程序或其它专门程序对它们做预处理。这是在程序执行前防止静态错 误的好办法,但预处理也会出错。 ▪ 数据内容错误:数据内容是指存储于存储单元或数据结构中的位串、字符串或数字。 数据内容本身没有特定的含义,除非通过硬件或软件给予解释。数据内容错误就是由于内容 被破坏或被错误地解释而造成的错误。 ▪ 数据结构错误:数据结构是指数据元素的大小和组织形式。在同一存储区域中可以 定义不同的数据结构。数据结构错误主要包括结构说明错误及把一个数据结构误当做另一类 数据结构使用的错误。这是更危险的错误。 ▪ 数据属性错误:数据属性是指数据内容的含义或语义。例如,整数、字符串、子程 序等等。数据属性错误主要包括:对数据属性不正确地解释,比如错把整数当实数,允许不 同类型数据混合运算而导致的错误等。 ⑤ 代码错误 主要包括:语法错误;打字错误;对语句或指令不正确理解所产生的错误。 (3) 按软件生存期阶段分类 Good enough-Gerhart 分类方法把软件的逻辑错误按生存期不同阶段分为 4 类。 ① 问题定义(需求分析)错误 它们是在软件定义阶段,分析员研究用户的要求后所编写的文档中出现的错误。换句话 说,这类错误是由于问题定义不满足用户的要求而导致的错误。 ② 规格说明错误 这类错误是指规格说明与问题定义不一致所产生的错误。它们又可以细分成: ▪ 不一致性错误:规格说明中功能说明与问题定义发生矛盾。 ▪ 冗余性错误:规格说明中某些功能说明与问题定义相比是多余的。 ▪ 不完整性错误:规格说明中缺少某些必要的功能说明。 ▪ 不可行错误:规格说明中有些功能要求是不可行的。 ▪ 不可测试错误:有些功能的测试要求是不现实的。 ③ 设计错误 这是在设计阶段产生的错误,它使系统的设计与需求规格说明中的功能说明不相符。它 们又可以细分为: ▪ 设计不完全错误:某些功能没有被设计,或设计得不完全。 ▪ 算法错误:算法选择不合适。主要表现为算法的基本功能不满足功能要求、算法不 可行或者算法的效率不符合要求。 ▪ 模块接口错误:模块结构不合理;模块与外部数据库的界面不一致,模块之间的界 面不一致。 ▪ 控制逻辑错误:控制流程与规格说明不一致;控制结构不合理。 ▪ 数据结构错误:数据设计不合理;与算法不匹配;数据结构不满足规格说明要求。 ④ 编码错误
编码过程中的错误是多种多样的,大体可归为以下几种:数据说明错、数据使用错、计 算错、比较错、控制流错、界面错、输入/输出错,及其它的错误。 在不同的开发阶段,错误的类型和表现形式是不同的,故应当采用不同的方法和策略来 进行检测。 3.软件测试的过程与策略 测试过程按4个步骤进行,即单元测试、组装测试、确认测试和系统测试。图5.3显示 出软件测试经历的4个步骤。单元测试集中对用源代码实现的每一个程序单元进行测试,检 査各个程序模块是否正确地实现了规定的功能。然后,进行集成测试,根据设计规定的软件 体系结构,把已测试过的模块组装起来,在组装过程中,检査程序结构组装的正确性。确认 测试则是要检査已实现的软件是否满足了需求规格说明中确定了的各种需求,以及软件配置 是否完全、正确。最后是系统测试,把已经经过确认的软件纳入实际运行环境中,与其它系 统成份组合在一起进行测试。严格地说,系统测试已超出了软件工程的范围。 被测模块/单元 测试 姿信息 它素 被测模块。/单元 测试 集成 确认 测试/已集成已确认测/可交付 已经过的软件 的软件 的软件 测试的 被薄模块。/单元)模块 图53软件测试的过程 (1)单元测试 单元测试针对程序模块,进行正确性检验的测试。其目的在于发现各模块内部可能存在 的各种差错。单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立 进行单元测试 ①单元测试的内容 ■模块接口测试:对通过被测模块的数据流进行测试。为此,对模块接口,包括参数 表、调用子模块的参数、全程数据、文件输入/输出操作都必须检査。 ■局部数据结构测试:设计测试用例检査数据类型说明、初始化、缺省值等方面的问 题,还要査清全程数据对模块的影响 路径测试:选择适当的测试用例,对模块中重要的执行路径进行测试。对基本执行 路径和循环进行测试可以发现大量的路径错误。 错误处理测试:检査模块的错误处理功能是否包含有错误或缺陷。例如,是否拒绝 不合理的输入:出错的描述是否难以理解、是否对错误定位有误、是否出错原因报告有误、 是否对错误条件的处理不正确;在对错误处理之前错误条件是否已经引起系统的干预等 边界测试:要特别注意数据流、控制流中刚好等于、大于或小于确定的比较值时出 错的可能性。对这些地方要仔细地选择测试用例,认真加以测试 此外,如果对模块运行时间有要求的话,还要专门进行关键路径测试,以确定最坏情况 下和平均意义下影响模块运行时间的因素。这类信息对进行性能评价是十分有用的
6 编码过程中的错误是多种多样的,大体可归为以下几种:数据说明错、数据使用错、计 算错、比较错、控制流错、界面错、输入/输出错,及其它的错误。 在不同的开发阶段,错误的类型和表现形式是不同的,故应当采用不同的方法和策略来 进行检测。 3. 软件测试的过程与策略 测试过程按 4 个步骤进行,即单元测试、组装测试、确认测试和系统测试。图 5.3 显示 出软件测试经历的 4 个步骤。单元测试集中对用源代码实现的每一个程序单元进行测试,检 查各个程序模块是否正确地实现了规定的功能。然后,进行集成测试,根据设计规定的软件 体系结构,把已测试过的模块组装起来,在组装过程中,检查程序结构组装的正确性。确认 测试则是要检查已实现的软件是否满足了需求规格说明中确定了的各种需求,以及软件配置 是否完全、正确。最后是系统测试,把已经经过确认的软件纳入实际运行环境中,与其它系 统成份组合在一起进行测试。严格地说,系统测试已超出了软件工程的范围。 图 5.3 软件测试的过程 (1) 单元测试 单元测试针对程序模块,进行正确性检验的测试。其目的在于发现各模块内部可能存在 的各种差错。单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立 进行单元测试。 ① 单元测试的内容 ▪ 模块接口测试 :对通过被测模块的数据流进行测试。为此,对模块接口,包括参数 表、调用子模块的参数、全程数据、文件输入/输出操作都必须检查。 ▪ 局部数据结构测试 :设计测试用例检查数据类型说明、初始化、缺省值等方面的问 题,还要查清全程数据对模块的影响。 ▪ 路径测试 : 选择适当的测试用例,对模块中重要的执行路径进行测试。对基本执行 路径和循环进行测试可以发现大量的路径错误。 ▪ 错误处理测试 :检查模块的错误处理功能是否包含有错误或缺陷。例如,是否拒绝 不合理的输入;出错的描述是否难以理解、是否对错误定位有误、是否出错原因报告有误、 是否对错误条件的处理不正确;在对错误处理之前错误条件是否已经引起系统的干预等。 ▪ 边界测试 :要特别注意数据流、控制流中刚好等于、大于或小于确定的比较值时出 错的可能性。对这些地方要仔细地选择测试用例,认真加以测试。 此外,如果对模块运行时间有要求的话,还要专门进行关键路径测试,以确定最坏情况 下和平均意义下影响模块运行时间的因素。这类信息对进行性能评价是十分有用的
②单元测试的步骤 通常单元测试在编码阶段进行。在源程序代码编制完成,经过评审和验证,确认没有语 法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,设计可以验证程序功能 找出程序错误的多个测试用例。对于每一组输入,应有预期的正确结果 模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些 辅助模块去模拟与被测模块相联系的其它模块。这些辅助模块分为两种: ■驱动模块:相当于被测模块的主 程序。它按收测试数据,把这些数据传「测试用例 驱动模块 测试结果 送给被测模块,最后输出实测结果 ■桩模块:用以代替被测模块调用 被测模块 的子模块。桩模块可以做少量的数据操 作,不需要把子模块所有功能都带进来 桩模块 桩模块 桩模块 但不允许什么事情也不做 图54单元测试的测试环境 被测模块、与它相关的驱动模块及 桩模块共同构成了一个“测试环境”,见图5.4 如果一个模块要完成多种功能,且以程序包或对象类的形式出现,例如Ada中的包 MODULA中的模块,C++中的类。这时可以将这个模块看成由几个小程序组成。对其中的每 个小程序先进行单元测试要做的工作,对关键模块还要做性能测试。对支持某些标准规程的 程序,更要着手进行互联测试。有人把这种情况特别称为模块测试,以区别单元测试。 (2)集成测试 在单元测试的基础上,需要将所有模块按照设计要求组装成为系统。这时需要考虑: 在把各个模块连接起来的时侯,穿越模块接口的数据是否会丢失 一个模块的功能是否会对另一个模块的功能产生不利的影响: ·各个子功能组合起来,能否达到预期要求的父功能 全局数据结构是否有问题 ■单个模块的误差累积起来,是否会放大,从而达到不能接受的程度。 单个模块的错误是否会导致数据库错误。 选择什么方式把模块组装起来形成一个可运行的系统,直接影响到模块测试用例的形 式、所用测试工具的类型、模块编号的次序和测试的次序、以及生成测试用例的费用和调试 的费用。通常,把模块组装成为系统的方式有两种方式: ①一次性集成方式 它是一种非增殖式集成方式。也叫做整体拼装。使用这种方式,首先对每个模块分别进 行模块测试,然后再把所有模块组装在一起进行测试,最终得到要求的软件系统 由于程序中不可避免地存在涉及模块间接口、全局数据结构等方面的问题,所以一次试 运行成功的可能性并不很大 ②增殖式集成方式 又称渐増式集成方式。首先对一个个模块进行模块测试,然后将这些模块逐步组装成较 大的系统,在组装的过程中边连接边测试,以发现连接过程中产生的问题。最后通过增殖逐 步组装成为要求的软件系统。 自顶向下的增殖方式:将模块按系统程序结构,沿控制层次自顶向下进行集成。由于 这种增殖方式在测试过程中较早地验证了主要的控制和判断点。在一个功能划分合理的程序 结构中,判断常出现在较高的层次,较早就能遇到。如果主要控制有问题,尽早发现它能够 减少以后的返工 自底向上的增殖方式:从程序结构的最底层模块开始组装和测试。因为模块是自底向
7 ② 单元测试的步骤 通常单元测试在编码阶段进行。在源程序代码编制完成,经过评审和验证,确认没有语 法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,设计可以验证程序功能、 找出程序错误的多个测试用例。对于每一组输入,应有预期的正确结果。 模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些 辅助模块去模拟与被测模块相联系的其它模块。这些辅助模块分为两种: ▪ 驱动模块:相当于被测模块的主 程序。它接收测试数据,把这些数据传 送给被测模块,最后输出实测结果。 ▪ 桩模块:用以代替被测模块调用 的子模块。桩模块可以做少量的数据操 作,不需要把子模块所有功能都带进来, 但不允许什么事情也不做。 被测模块、与它相关的驱动模块及 桩模块共同构成了一个“测试环境”,见图 5.4。 如果一个模块要完成多种功能,且以程序包或对象类的形式出现,例如 Ada 中的包, MODULA 中的模块,C++中的类。这时可以将这个模块看成由几个小程序组成。对其中的每 个小程序先进行单元测试要做的工作,对关键模块还要做性能测试。对支持某些标准规程的 程序,更要着手进行互联测试。有人把这种情况特别称为模块测试,以区别单元测试。 (2) 集成测试 在单元测试的基础上,需要将所有模块按照设计要求组装成为系统。这时需要考虑: ▪ 在把各个模块连接起来的时侯,穿越模块接口的数据是否会丢失; ▪ 一个模块的功能是否会对另一个模块的功能产生不利的影响; ▪ 各个子功能组合起来,能否达到预期要求的父功能; ▪ 全局数据结构是否有问题; ▪ 单个模块的误差累积起来,是否会放大,从而达到不能接受的程度。 ▪ 单个模块的错误是否会导致数据库错误。 选择什么方式把模块组装起来形成一个可运行的系统,直接影响到模块测试用例的形 式、所用测试工具的类型、模块编号的次序和测试的次序、以及生成测试用例的费用和调试 的费用。通常,把模块组装成为系统的方式有两种方式: ① 一次性集成方式 它是一种非增殖式集成方式。也叫做整体拼装。使用这种方式,首先对每个模块分别进 行模块测试,然后再把所有模块组装在一起进行测试,最终得到要求的软件系统。 由于程序中不可避免地存在涉及模块间接口、全局数据结构等方面的问题,所以一次试 运行成功的可能性并不很大。 ② 增殖式集成方式 又称渐增式集成方式。首先对一个个模块进行模块测试,然后将这些模块逐步组装成较 大的系统,在组装的过程中边连接边测试,以发现连接过程中产生的问题。最后通过增殖逐 步组装成为要求的软件系统。 ▪ 自顶向下的增殖方式:将模块按系统程序结构,沿控制层次自顶向下进行集成。由于 这种增殖方式在测试过程中较早地验证了主要的控制和判断点。在一个功能划分合理的程序 结构中,判断常出现在较高的层次,较早就能遇到。如果主要控制有问题,尽早发现它能够 减少以后的返工。 ▪ 自底向上的增殖方式:从程序结构的最底层模块开始组装和测试。因为模块是自底向 图 5.4 单元测试的测试环境
上进行组装,对于一个给定层次的模块,它的子模块(包括子模块的所有下属模块)已经组 装并测试完成,所以不再需要桩模块。在模块的测试过程中需要从子模块得到的信息可以直 接运行子模块得到 ③混合增殖式测试:自顶向下増殖的方式和自底向上增殖的方式各有优缺点。自顶向 下増殖方式的缺点是需要建立桩模块。要使桩模块能够模拟实际子模块的功能将是十分困难 的。同时涉及复杂算法和真正输入/输出的模块一般在底层,它们是最容易出问题的模块, 到组装和测试的后期才遇到这些模块,一旦发现问题,导致过多的回归测试。而自顶向下增 殖方式的优点是能够较早地发现在主要控制方面的问题。自底向上增殖方式的缺点是“程序 直未能做为一个实体存在,直到最后一个模块加上去后才形成一个实体”。就是说,在自底 向上组装和测试的过程中,对主要的控制直到最后才接触到。但这种方式的优点是不需要桩 模块,而建立驱动模块一般比建立桩模块容易,同时由于涉及到复杂算法和真正输入/输出 的模块最先得到组装和测试,可以把最容易出问题的部分在早期解决。此外自底向上增殖的 方式可以实施多个模块的并行测试 有鉴于此,通常是把以上两种方式结合起来进行组装和测试。 ■衍变的自顶向下的增殖测试:它的基本思想是强化对输入/输出模块和引入新算法模 块的测试,并自底向上组装成为功能相当完整且相对独立的子系统,然后由主模块开始自顶 向下进行增殖测试。 自底向上-自顶向下的增殖测试:它首先对含读操作的子系统自底向上直至根结点模块 进行组装和测试,然后对含写操作的子系统做自顶向下的组装与测试。 回归测试:这种方式采取自顶向下的方式测试被修改的模块及其子模块,然后将这 部分视为子系统,再自底向上测试,以检查该子系统与其上级模块的接口是否适配。 (3)确认测试 确认测试又称有效性测试。它的任务是验证软件的有效性,即验证软件的功能和性能及 其它特性是否与用户的要求一致。在软件需求规格说明书描述了全部用户可见的软件属性, 其中有一节叫做有效性准则,它包含的信息就是软件确认测试的基础 在确认测试阶段需要做的工作如图5.5所示。首先要进行有效性测试以及软件配置复审, 然后进行验收测试和安装测试,在通过了专家鉴定之后,才能成为可交付的软件。 择测试人 构造测试用例 性测试报 测试 实际运行测试 专家交用户 软件计划 机构 鉴定 裁决 会运行维护 用户文档 软件 开发文档 配置软件配置 审查 源程序文本 支持环境 图5.5确认测试的步骤 ①进行有效性测试(功能测试)
8 上进行组装,对于一个给定层次的模块,它的子模块(包括子模块的所有下属模块)已经组 装并测试完成,所以不再需要桩模块。在模块的测试过程中需要从子模块得到的信息可以直 接运行子模块得到。 ③ 混合增殖式测试:自顶向下增殖的方式和自底向上增殖的方式各有优缺点。自顶向 下增殖方式的缺点是需要建立桩模块。要使桩模块能够模拟实际子模块的功能将是十分困难 的。同时涉及复杂算法和真正输入/输出的模块一般在底层,它们是最容易出问题的模块, 到组装和测试的后期才遇到这些模块,一旦发现问题,导致过多的回归测试。而自顶向下增 殖方式的优点是能够较早地发现在主要控制方面的问题。自底向上增殖方式的缺点是“程序 一直未能做为一个实体存在,直到最后一个模块加上去后才形成一个实体”。就是说,在自底 向上组装和测试的过程中,对主要的控制直到最后才接触到。但这种方式的优点是不需要桩 模块,而建立驱动模块一般比建立桩模块容易,同时由于涉及到复杂算法和真正输入/输出 的模块最先得到组装和测试,可以把最容易出问题的部分在早期解决。此外自底向上增殖的 方式可以实施多个模块的并行测试。 有鉴于此,通常是把以上两种方式结合起来进行组装和测试。 ▪ 衍变的自顶向下的增殖测试:它的基本思想是强化对输入/输出模块和引入新算法模 块的测试,并自底向上组装成为功能相当完整且相对独立的子系统,然后由主模块开始自顶 向下进行增殖测试。 ▪ 自底向上-自顶向下的增殖测试:它首先对含读操作的子系统自底向上直至根结点模块 进行组装和测试,然后对含写操作的子系统做自顶向下的组装与测试。 ▪ 回归测试:这种方式采取自顶向下的方式测试被修改的模块及其子模块,然后将这一 部分视为子系统,再自底向上测试,以检查该子系统与其上级模块的接口是否适配。 (3) 确认测试 确认测试又称有效性测试。它的任务是验证软件的有效性,即验证软件的功能和性能及 其它特性是否与用户的要求一致。在软件需求规格说明书描述了全部用户可见的软件属性, 其中有一节叫做有效性准则,它包含的信息就是软件确认测试的基础。 在确认测试阶段需要做的工作如图 5.5 所示。首先要进行有效性测试以及软件配置复审, 然后进行验收测试和安装测试,在通过了专家鉴定之后,才能成为可交付的软件。 图 5.5 确认测试的步骤 ① 进行有效性测试(功能测试)
有效性测试是在模拟的环境(可能就是开发的环境)下,运用黑盒测试的方法,验证被 测软件是否满足需求规格说明书列出的需求。为此,需要首先制定测试计划,规定要做测试 的种类。还需要制定一组测试步骤,描述具体的测试用例。通过实施预定的测试计划和测试 步骤,确定软件的特性是否与需求相符,确保所有的软件功能需求都能得到满足,所有的软 件性能需求都能达到,所有的文档都是正确且便于使用。同时,对其它软件需求,例如可移 植性、兼容性、出错自动恢复、可维护性等,也都要进行测试,确认是否满足。 ②软件配置复查 软件配置复查的目的是保证软件配置的所有成分都齐全,各方面的质量都符合要求,具 有维护阶段所必需的细节,而且已经编排好分类的目录 除了按合同规定的内容和要求,由人工审查软件配置之外,在确认测试的过程中,应当 严格遵守用户手册和操作手册中规定的使用步骤,以便检査这些文档资料的完整性和正确性。 必须仔细记录发现的遗漏和错误,并且适当地补充和改正 ③验收测试 在通过了系统的有效性测试及软件配置审査之后,就应开始系统的验收测试。验收测试 是以用户为主的测试。软件开发人员和QA(质量保证)人员也应参加。由用户参加设计测 试用例,使用用户界面输入测试数据,并分析测试的输出结果。一般使用生产中的实际数据 进行测试。在测试过程中,除了考虑软件的功能和性能外,还应对软件的可移植性、兼容性 可维护性、错误的恢复功能等进行确认。 ④a测试和β测试 在软件交付使用之后,用户将如何实际使用程序,对于开发者来说是无法预测的。因为 用户在使用过程中常常会发生对使用方法的误解、异常的数据组合、以及产生对某些用户来 说似乎是清晰的但对另一些用户来说却难以理解的输出等等。 如果软件是为多个用户开发的产品的时侯,让每个用户逐个执行正式的验收测试是不切 实际的。很多软件产品生产者采用一种称之为a测试和β测试的测试方法,以发现可能只有 最终用户才能发现的错误 a测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操 作环境下进行的测试。这是在受控制的环境下进行的测试。a测试的目的是评价软件产品的 FURPS(即功能、可使用性、可靠性、性能和支持)。尤其注重产品的界面和特色。α测试 人员是除开产品开发人员之外首先见到产品的人,他们提出的功能和修改意见是特别有价值 的。α测试可以从软件产品编码结束之时开始,或在模块(子系统)测试完成之后开始,也 可以在确认测试过程中产品达到一定的稳定和可靠程度之后再开始。有关的手册(草稿)等 应事先准备好。 β测试是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。与a测试 不同的是,开发者通常不在测试现场。因而,β测试是在开发者无法控制的环境下进行的软 件现场应用。在β测试中,由用户记下遇到的所有问题,包括真实的以及主观认定的,定期 向开发者报告,开发者在综合用户的报告之后,做出修改,最后将软件产品交付给全体用户 使用。B测试主要衡量产品的 FURPS。着重于产品的支持性,包括文档、客户培训和支持产 品生产能力。只有当α测试达到一定的可靠程度时,才能开始β测试。由于它处在整个测试 的最后阶段,不能指望这时发现主要问题。同时,产品的所有手册文本也应该在此阶段完全 定稿。由于β测试的主要目标是测试可支持性,所以β测试应尽可能由主持产品发行的人员 来管理 (4)系统测试 所谓系统测试,是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计 算机硬件、外设、某些支持软件、数据和人员等其它系统元素结合在一起,在实际运行(使
9 有效性测试是在模拟的环境(可能就是开发的环境)下,运用黑盒测试的方法,验证被 测软件是否满足需求规格说明书列出的需求。为此,需要首先制定测试计划,规定要做测试 的种类。还需要制定一组测试步骤,描述具体的测试用例。通过实施预定的测试计划和测试 步骤,确定软件的特性是否与需求相符,确保所有的软件功能需求都能得到满足,所有的软 件性能需求都能达到,所有的文档都是正确且便于使用。同时,对其它软件需求,例如可移 植性、兼容性、出错自动恢复、可维护性等,也都要进行测试,确认是否满足。 ② 软件配置复查 软件配置复查的目的是保证软件配置的所有成分都齐全,各方面的质量都符合要求,具 有维护阶段所必需的细节,而且已经编排好分类的目录。 除了按合同规定的内容和要求,由人工审查软件配置之外,在确认测试的过程中,应当 严格遵守用户手册和操作手册中规定的使用步骤,以便检查这些文档资料的完整性和正确性。 必须仔细记录发现的遗漏和错误,并且适当地补充和改正。 ③ 验收测试 在通过了系统的有效性测试及软件配置审查之后,就应开始系统的验收测试。验收测试 是以用户为主的测试。软件开发人员和 QA(质量保证)人员也应参加。由用户参加设计测 试用例,使用用户界面输入测试数据,并分析测试的输出结果。一般使用生产中的实际数据 进行测试。在测试过程中,除了考虑软件的功能和性能外,还应对软件的可移植性、兼容性、 可维护性、错误的恢复功能等进行确认。 ④ α测试和β测试 在软件交付使用之后,用户将如何实际使用程序,对于开发者来说是无法预测的。因为 用户在使用过程中常常会发生对使用方法的误解、异常的数据组合、以及产生对某些用户来 说似乎是清晰的但对另一些用户来说却难以理解的输出等等。 如果软件是为多个用户开发的产品的时侯,让每个用户逐个执行正式的验收测试是不切 实际的。很多软件产品生产者采用一种称之为α测试和β测试的测试方法,以发现可能只有 最终用户才能发现的错误。 α测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操 作环境下进行的测试。这是在受控制的环境下进行的测试。α测试的目的是评价软件产品的 FURPS(即功能、可使用性、可靠性、性能和支持)。尤其注重产品的界面和特色。α测试 人员是除开产品开发人员之外首先见到产品的人,他们提出的功能和修改意见是特别有价值 的。α测试可以从软件产品编码结束之时开始,或在模块(子系统)测试完成之后开始,也 可以在确认测试过程中产品达到一定的稳定和可靠程度之后再开始。有关的手册(草稿)等 应事先准备好。 β测试是由软件的多个用户在一个或多个用户的实际使用环境下进行的测试。与α测试 不同的是,开发者通常不在测试现场。因而,β测试是在开发者无法控制的环境下进行的软 件现场应用。在β测试中,由用户记下遇到的所有问题,包括真实的以及主观认定的,定期 向开发者报告,开发者在综合用户的报告之后,做出修改,最后将软件产品交付给全体用户 使用。β测试主要衡量产品的 FURPS。着重于产品的支持性,包括文档、客户培训和支持产 品生产能力。只有当α测试达到一定的可靠程度时,才能开始β测试。由于它处在整个测试 的最后阶段,不能指望这时发现主要问题。同时,产品的所有手册文本也应该在此阶段完全 定稿。由于β测试的主要目标是测试可支持性,所以β测试应尽可能由主持产品发行的人员 来管理。 (4) 系统测试 所谓系统测试,是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计 算机硬件、外设、某些支持软件、数据和人员等其它系统元素结合在一起,在实际运行(使
用)环境下,对计算机系统进行一系列的组装测试和确认测试 系统测试的目的在于通过与系统的需求定义作比较,发现软件与系统定义不符合或与之 矛盾的地方。系统测试的测试用例应根据需求分析规格说明来设计,并在实际使用环境下来 运行 4.测试用例设计 (1)测试方法概述 软件测试的种类大致可以分为人工测试和基于计算机的测试。而基于计算机的测试由可 以分为白盒测试和黑盒测试 ①黑盒测试 根据软件产品的功能设计规格,在计算机上进行测试,以证实每个实现了的功能是否符 合要求。这种测试方法就是黑盒测试。黑盒测试意味着测试要在软件的接口处进行。就是说, 这种方法是把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特 性,只依据程序的需求分析规格说明,检査程序的功能是否符合它的功能说明。 用黑盒测试发现程序中的错误,必须在所有可能的输入条件和输出条件中确定测试数 据,来检查程序是否都能产生正确的输出 ②白盒测试 根据软件产品的内部工作过程,在计算机上进行测试,以证实每种内部操作是否符合设 计规格要求,所有内部成分是否已经过检查。这种测试方法就是白盒测试。白盒测试把测试 对象看做一个打开的盒子,允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择 测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,确定实际的状态 是否与预期的状态一致 不论是黑盒测试,还是白盒测试,都不可能把所有可能的输入数据都拿来进行所谓的穷 举测试。因为可能的测试输入数据数目往往达到天文数字。下面让我们看两个例子 假设一个程序P有输入X和Y及输出Z,参看图56 在字长为32位的计算机上运行。如果X、Y只取整数,考 虑把所有的X、Y值都做为测试数据,按黑盒测试方法进 P 行穷举测试,力图全面、无遗漏地“挖掘”出程序中的所Y 有错误。这样做可能采用的测试数据组(X,Y)的最大可 能数目为:232×232=26。如果程序P测试一组Ⅹ、Y数据 图56黑盒子 需要1毫秒,且一天工作24小时,一年工作365天,要完成264组测试,需要5亿年。 循环≤20次 图5.7白盒测试中的穷举测试 而对一个具有多重选择和循环嵌套的程序,不同的路径数目也可能是天文数字。设给出
10 图 5.6 黑盒子 用)环境下,对计算机系统进行一系列的组装测试和确认测试。 系统测试的目的在于通过与系统的需求定义作比较,发现软件与系统定义不符合或与之 矛盾的地方。系统测试的测试用例应根据需求分析规格说明来设计,并在实际使用环境下来 运行。 4. 测试用例设计 (1) 测试方法概述 软件测试的种类大致可以分为人工测试和基于计算机的测试。而基于计算机的测试由可 以分为白盒测试和黑盒测试。 ① 黑盒测试 根据软件产品的功能设计规格,在计算机上进行测试,以证实每个实现了的功能是否符 合要求。这种测试方法就是黑盒测试。黑盒测试意味着测试要在软件的接口处进行。就是说, 这种方法是把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特 性,只依据程序的需求分析规格说明,检查程序的功能是否符合它的功能说明。 用黑盒测试发现程序中的错误,必须在所有可能的输入条件和输出条件中确定测试数 据,来检查程序是否都能产生正确的输出。 ② 白盒测试 根据软件产品的内部工作过程,在计算机上进行测试,以证实每种内部操作是否符合设 计规格要求,所有内部成分是否已经过检查。这种测试方法就是白盒测试。白盒测试把测试 对象看做一个打开的盒子,允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择 测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,确定实际的状态 是否与预期的状态一致。 不论是黑盒测试,还是白盒测试,都不可能把所有可能的输入数据都拿来进行所谓的穷 举测试。因为可能的测试输入数据数目往往达到天文数字。下面让我们看两个例子。 假设一个程序 P 有输入 X 和 Y 及输出 Z,参看图 5.6。 在字长为 32 位的计算机上运行。如果 X、Y 只取整数,考 虑把所有的 X、Y 值都做为测试数据,按黑盒测试方法进 行穷举测试,力图全面、无遗漏地“挖掘”出程序中的所 有错误。这样做可能采用的测试数据组(Xi, Yi)的最大可 能数目为:2 32×2 32=2 64。如果程序 P 测试一组 X、Y 数据 需要 1 毫秒,且一天工作 24 小时,一年工作 365 天,要完成 2 64组测试,需要 5 亿年。 图 5.7 白盒测试中的穷举测试 而对一个具有多重选择和循环嵌套的程序,不同的路径数目也可能是天文数字。设给出