软件测试的基本概念¶
第 2 章¶
软件测试的基本概念¶
第 1 章着重介绍了为什么要进行软件测试和什么是软件测试,从而使我们认识到软件测试是软件质量保证的重要手段之一。软件测试的主要目的之一就是为了发现软件中存在的缺陷。所以要做好测试,首先就要了解什么是缺陷。而要了解什么是缺陷,就必须清楚 “质量” 的概念,因为缺陷是相对质量而存在的,违背了质量、违背了客户的意愿,不能满足客户的要求,就会引起缺陷或产生缺陷,图 2-1 描述了客户、质量、缺陷和测试的关系。概括地说,没有满足质量要求、和质量冲突的东西就是缺陷,缺陷是质量的对立面。只有深刻地理解质量的内涵,才能更早、更多地发现软件产品中的缺陷。

本章从软件质量出发,了解软件质量内涵,然后引出软件缺陷的产生原因、种类和代价等。最后,将全面介绍软件测试相关的概念,包括软件测试的分类、测试的不同阶段、测试工作的具体内容和范畴等,使读者完整地理解软件测试的基本内涵。
2.1 软件缺陷¶
正如前面所说,要了解缺陷,就必须理解 “质量” 的概念,理解软件质量的内涵。软件产品具有一般产品的共性,也有其独具的特性,软件产品的质量概念是建立在一般产品质量概念及理论的基础之上,同时由于软件本身的特性,而具有不同的内涵。下面,围绕软件质量和软件缺陷展开讨论,例如:
(5) 不同的阶段所产生的缺陷,带来多大的成本?
2.1.1 软件质量的内涵¶
世界著名的质量管理专家朱兰为 “质量” 给出一个确切的含义,满足使用要求的基础是质量特征,产品的任何特性(性质、属性等)、材料或满足使用要求的过程都是质量特征。从而,演变为国际标准化的定义,即 1986 年 ISO8492 中所给出的质量定义:质量是产品或服务所满足明示或暗示需求能力的固有特性和特征的集合。
(1)固有特性是指某事物中本来就有的,尤其是那种永久的特性,例如,木材的硬度、桌子的高度、声音的频率和螺栓的直径等技术特性。
(2)明示的特性,可以理解为是规定的要求,一般在国家标准、行业规范、产品说明书或产品设计规格说明书中进行描述或客户明确提出的要求,如计算机的尺寸、重量、内存和接口等,用户可以查看。
(3)暗示的特性是由社会习俗约定、行为惯例所要求的一种潜规则、不言而喻的。一般情况下,文档中不会给出明确的规定,组织应根据自身产品的用途和特性进行识别,并做出规定。比如一张 4 条腿的餐桌,只要告诉一条腿的高度就可以了,暗示着另外三条腿必须具有相同高度。
而在 IBM RUP (统一过程) 中,质量被定义为 “满足或超出认定的一组需求,并使用经过认可的评测方法和标准来评估,还使用认定的流程来生产”。因此,质量不是简单地满足用户的需求,还要包含证明质量达标所使用的评测方法和标准,以及如何实施可管理、可重复使用的流程,以确保由此流程生产的产品已达到预期的、稳定的质量水平。
软件质量与传统意义上的质量概念并无本质差别,只是软件质量拥有一些自身的特性,这也是由软件的特点所决定的。例如,Barry Boehm 从计算机软件角度看,认为软件质量是 “达到高水平的用户满意度、接口性、维护性、强壮性和适用性” 的体现。1983 年,ANSI/IEEE STD729 给出了软件质量定义 —— 软件产品满足规定的和隐含的与需求能力有关的全部特征和特性,它包括:
(1) 软件产品质量满足用户要求的程度;
(2) 软件各种属性的组合程度;
(3) 用户对软件产品的综合反映程度;
(4) 软件在使用过程中满足用户要求的程度。
这些特性反映了在人们日常生活中所说的软件系统的易用性、功能性、有效性、可靠性和性能等方面。如 RUP 将软件产品质量定义为三个维度的质量,其中功能和性能是大家非常熟悉的质量特性,可靠性也不陌生,与稳定性比较接近。
(1) 功能:按照既定意图和要求,执行指定用例的能力。
(2) 性能:系统的资源利用率和操作特征。资源利用率包括 CPU、内存等所占有的程度。性能的操作特征包括与作业负载相关的特征,如响应时间、操作可靠性 (Mean Time To Failure, MTTF), 以及与操作限制相关的特征,如负载容量或强度。
(3)可靠性:软件坚固性和可靠性(防故障能力,如防止崩溃、内存丢失等能力)、代码完整性以及技术兼容性等。
如果进一步展开这三维质量特性,可以分析更多的、特定的产品质量属性。正如 McCall 模型 (如图 2-2 所示) 所描述的。

除了 McCall 模型,还有其他产品质量模型,如 Boehm 模型、ISO 9126 模型。如图 2-3 所示的 ISO 9126 三层质量模型,被国内和国际标准采用。

根据这些质量模型,软件产品质量可以归纳为以下几个属性。
根据标准 ISO/IEC TR 9126 (2003) 或新的 ISO/IEC 25000 (2010) 系列标准,软件质量分为内部质量、外部质量、使用质量,而且具有下列关系,如图 2-4 所示。其中,外部质量如 ISO 9126 SQRC 所描述的,而纯内部质量包括需求的可追溯性、软件规模、代码的复杂度、软件信息流复杂度、代码耦合性、数据耦合性、模块化、变量命名、程序规范性等。

从 ISO/IEC 25000 标准看,软件测试还要关注使用质量,如图 2-5 所示。在使用质量中,不仅包含基本的功能和非功能特性,如功能 (有效、有用)、效率 (性能)、安全性等,还要求用户在使用软件产品过程中获得愉悦,对产品信任,产品也不应该给用户带来经济、健康和环境等风险,并能处理好业务的上下文关系 (语境), 覆盖完整的业务领域。

2.1.2 软件缺陷的定义¶
对于软件存在的各种问题,人们常用 “软件缺陷” 这个词,在英文中人们喜欢用一个形象的词 “Bug (臭虫)” 来代替 “Defect (缺陷)” 一词。实际上,与 “缺陷 (Bug)” 相近的词还有很多,例如:
| 缺点(Defect) | 偏差(Variance) |
| 谬误(Fault) | 失败(Failure) |
| 问题(Problem) | 矛盾(Inconsistency) |
| 错误(Error) | 毛病(Incident) |
| 异常(Anomy) |
软件缺陷的含义相对比较广泛,包含各种偏差、谬误或错误,其结果表现在功能上的失败和不符合设计要求、客户的实际需求,即与需求相矛盾。所以,软件缺陷是指计算机系统或者程序中存在的任何一种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷、瑕疵,其结果会导致软件产品在某种程度上不能满足用户的需要。在 IEEE Standard 729 (1983) 中对软件缺陷给出了一个标准的定义。
软件缺陷就是软件产品中所存在的问题,最终表现为用户所需要的功能没有完全实现,没有满足用户的需求。而软件缺陷表现的形式是各种各样的,不仅体现在功能的失效方面,还体现在其他方面,例如:
2.1.3 软件缺陷的产生¶
如前所说,由于软件系统越来越复杂,不管是需求分析、程序设计等都面临越来越大的挑战。由于软件开发人员思维上的主观局限性,且目前开发的软件系统都具有相当的复杂性,决定了在开发过程中出现软件错误是不可避免的。造成软件缺陷的主要原因有哪些?可以从软件本身、团队工作和技术问题等多个方面分析,以确定造成软件缺陷的主要因素。
1. 技术问题¶
(1) 开发人员技术的限制,系统设计不能够全面考虑功能、性能和安全性的平衡。
(2) 刚开始采用新技术,解决和处理问题时不够成熟。
(3) 由于逻辑过于复杂,很难在第一次就将问题全部处理好。
(4) 系统结构设计不合理或算法不科学,造成系统性能低下。
(5) 接口参数太多,导致参数传递不匹配。
(6) 需求规格说明书中有些功能在技术上无法实现。
(7)没有考虑系统崩溃后的自我恢复或数据的异地备份、灾难性恢复等需求,导致系统存在安全性、可靠性的隐患。
(8) 一般情况下,对应的编程语言编译器可以发现这类问题;对于解释性语言,只能在测试运行的时候发现。
2. 软件本身¶
(1) 不完善的软件开发标准或开发流程。
(2) 文档错误、内容不正确或拼写错误。
(3) 没有考虑大量数据使用场合,从而可能会引起强度或负载问题。
(4) 对程序逻辑路径或数据范围的边界考虑不够周全,漏掉某几个边界条件造成的问题。
(5) 对一些实时应用系统,缺乏整体考虑和精心设计,忽视了时间同步的要求,从而引起系统各单元之间不协调、不一致性的问题。
(6) 与硬件、第三方系统软件之间存在接口或依赖性。
3. 团队工作¶
(1) 团队文化,如对软件质量不够重视。
(2)系统分析时对客户的需求不是十分清楚,或者和用户的沟通存在一些困难,从而造成对用户需求的误解或理解不够全面。
(3)不同阶段的开发人员相互理解不一致,软件设计对需求分析结果的理解偏差,编程人员对系统设计规格说明书中某些内容重视不够,或存在着误解。
(4)设计或编程上的一些假定或依赖性,没有得到充分的沟通。
2.1.4 软件缺陷的构成¶
软件缺陷是由很多原因造成的,如果把它们按需求分析结果 —— 规格说明书、系统设计结果、编程的代码等归类起来,比较后发现,结果规格说明书是软件缺陷出现最多的地方,见图 2-6。
软件产品规格说明书为什么是软件缺陷存在最多的地方?主要原因有以下几种。
排在产品规格说明书之后的是设计,编程排在第三位。在许多人的印象中,软件测试主要是找程序代码中的错误,这是一个认识的误区。如果从软件开发各个阶段能够发现软件缺陷数目看,比较理想的情况也主要集中在需求分析、系统设计、编程阶段 (包括单元测试) 等三个阶段中,而在系统测试阶段,能够发现的缺陷数目不应该多,即经过需求评审、设计评审、代码评审、单元测试以后,系统中存在的缺陷数目就比较少,会大大降低企业成本,这就是 2.1.5 节要讨论的缺陷成本。
2.1.5 修复软件缺陷的代价¶
美国商务部国家标准和技术研究所 (NIST) 进行的一项研究表明,软件缺陷每年给美国经济造成的损失高达几百亿甚至上千亿美元。说明软件中存在的缺陷所造成的损失是巨大的。即使在软件企业内部,软件缺陷同样会给企业带来很大的成本,即软件缺陷产生劣质成本。根据统计数据,多数软件企业的这种劣质成本高达开发总成本的 40%\~50%。
鉴于这样高的劣质成本,必须足够地重视软件缺陷所引起的代价,这也就是为什么在讨论软件测试时,总是要强调,希望软件测试尽早介入项目,问题发现得越早越好。缺陷被发现之后,要尽快修复这些被发现的缺陷。为什么要这样做呢?原因很简单,缺陷发现或解决得越迟,成本就越高。
由于人的认识不可能百分之百地符合客观实际,因此生命周期每个阶段的工作中都可能发生错误。并不只是在编程阶段产生错误,需求和设计阶段同样会产生错误。由于前一阶段的成果是后一阶段工作的基础,前一阶段的错误自然会导致后一阶段的工作结果中有相应的错误,而且错误会逐渐累积,越来越多。也许一开始,只是一个很小范围内的潜在错误,但随着产品开发工作的进行,错误不断传导而被放大,小错误会扩散成大错误。越到后期,修改缺陷所付出的代价越大。例如,需求定义中存在的一个问题,没有及时发现,等设计、编程工作都完成之后才被发现,这时就不得不修改设计、修改代码,可见返工的涉及面很广,返工的工作量也很大。如果问题到了发布之后被发现,损失就更大。总之,错误不能及早发现,那只可能造成越来越严重的后果。若能及早排除软件开发中的错误,有效地减少后期工作可能遇到的问题,就可以尽可能地避免付出高昂的代价,从而大大提高系统开发过程的效率。前期的缺陷发现还能减少缺陷的注入量,从根本上提高产品的质量。
Boehm 在 Software Engineering Economics (1981) 一书中写到:平均而言,如果在需求阶段修正一个错误的代价是 1,那么,在设计阶段就是它的 3~6 倍,在编程阶段是它的 10 倍,在内部测试阶段是它的 20~40 倍,在外部测试阶段是它的 30~70 倍,而到了产品发布出去时,这个数字就是 \(40\sim 100\) 倍。修正错误的代价不是随时间线性增长,而几乎是呈指数增长的,参见图 2-7。
2.2 软件测试的分类¶
分类取决于分类的方法和坐标,对于软件测试,可以从不同的角度加以分类。软件测试可以根据测试的方法进行分类,也可以根据测试的对象、测试的目标和测试的阶段进行分类,如图 2-8 所示。通过分类,读者能够了解软件测试的全貌,对软件测试有一个完整的认识。

1. 按测试层次分¶
按测试层次划分可以分为 4 个层次。
要的产品特性,验收测试关注用户环境、用户数据,而且用户也参与测试过程中。
2. 按被测试的对象 (单元 / 组件、文档、子系统、系统等) 分类¶
(1)单元测试 (Unit Testing),包括组件测试 (Component Testing)、模块测试 (Module Testing) 等。
3. 按测试阶段划分¶
对于传统的软件测试流程,一般分为需求评审、设计评审、单元测试、集成测试、系统测试、验收测试、 \(\alpha\) 测试、 \(\beta\) 测试等阶段。如果是敏捷测试流程,一般分为测试需求分析、迭代测试计划、持续的单元和系统测试、验收测试等。按阶段划分不一定科学,不同的测试流程则可能得到不一样的结果,如传统测试流程和敏捷测试流程就差别较大。
4. 按测试目的分类¶
按测试目的可以分为集成测试、功能测试、回归测试、性能测试、可靠性测试、安全性测试和兼容性测试等,这些也可以称为 “测试类型”。
5. 其他分类¶
2.3 静态测试和动态测试¶
根据程序是否运行,测试可以分为静态测试和动态测试。早期将测试局限于对程序进行动态测试,可以看作是狭义的测试概念,而现在将需求和设计的评审也纳入测试的范畴,可以看作是广义的测试概念或现代的测试概念。
静态测试包括对软件产品的需求和设计规格说明书的评审、对程序代码的审查以及静态分析等。动态测试是通过真正运行程序发现错误,通过观察代码运行过程,来获取系统行为、变量实时结果、内存、堆栈、线程以及测试覆盖度等各方面的信息,来判断系统是否存在问题,或者通过有效的测试用例,对应的输入输出关系来分析被测程序的运行情况,来发现缺陷。在 SWEBOK 3.0 中也认可静态测试,只是把这部分内容放在 “质量管理” 模块。这里侧重介绍静态测试(产品评审和静态分析),以后会更多地讨论动态测试。
2.3.1 产品评审¶
软件评审的重要目的就是通过软件评审尽早地发现产品中的缺陷,因此软件评审可以看作软件测试的有机组成部分,两者之间有着密不可分的关系。通过软件评审,可以更早地发现需求工程、软件设计等各个方面的问题,极大地减少后期返工,将质量成本从昂贵的后期返工转化为前期的缺陷发现。通过评审,还可以将问题记录下来,使其具有可追溯性,找出问题产生的根本原因,在将来的项目开发中进一步减少缺陷,有利于软件质量的提高。
那什么是软件评审呢?根据 IEEE Std 1028—1988 的定义:评审是对软件元素或者项目状态的一种评估手段,以确定其是否与计划的结果保持一致,并使其得到改进。检验工作产品是否正确地满足了以往工作产品中建立的规范,如需求或设计文档是否符合所定义的模板要求,各项内容是否清楚、一致。
软件评审的形式有互为评审 (Peer Review)、走查 (Walk-through) 和会议评审 (Inspection)。互为评审也称同行评审,甲完成的成果 (如需求文档或代码) 由乙来检查,乙完成的成果则由甲来检查。走查是由他人从头到尾进行检查,而会议评审是最为正式的集体检审查形式,由主持人 (协调人)、作者和相关专业人员、项目干系人等共同参与,经过一系列准备工作 (如选择合适的参加人员、开预备会、发放材料、事先阅读等),开会确定存在的各种问题,并事后跟踪、解决问题。
软件评审的对象有很多种,主要分为管理评审、技术评审、文档评审和流程评审。对于软件测试,应该包含需求评审、设计评审、代码评审和文档评审,而管理评审和流程评审则属于软
件质量保证的组织和过程管理的活动内容。
1. 需求评审¶
需求,如需求分析规格说明书,主要审查其是否完整、正确、清晰,这是软件开发成败的关键。为了保证需求定义的质量,应对其进行严格的审查。测试人员要参与系统或产品需求分析,认真阅读有关用户需求分析文档,真正理解客户的需求,检查规格说明书对产品描述的准确性、一致性等,为今后熟悉应用系统、编写测试计划、设计测试用例等做好准备工作。需求评审,也包含文档评审,对文档格式、术语、内容等进行检查,检查文档格式是否满足标准、术语是否前后一致以及内容是否正确、易理解等。
2. 设计和代码评审¶
软件设计是基于对用户需求的理解基础上,借助计算机技术,将客户的需求转换成计算机软件表示的过程,其设计的结果能描述出系统结构和逻辑、数据输入、详细处理过程、数据存储模式、数据输出等。例如,可以按照功能性需求或非功能性需求等,对系统结构的合理性、可测试性等进行分析检查,还可以利用关系数据库的规范化理论对数据库模式进行审查。
代码会审是由一组人通过阅读、讨论来审查程序结构、代码风格、算法等的过程。会审小组会前充分阅读待审程序文本、控制流程图及有关要求、规范等;在评审会上程序员逐句讲解程序的逻辑并回答其他人员提出的问题,对有争议的问题进行讨论,以达成一致意见或得到解决方案。实践表明,代码会审做得好的话可以发现大部分程序缺陷,甚至程序员在自己讲解过程中就能发现不少代码错误,而讨论可能进一步促使问题暴露。例如,对某个全局变量的默认值改变或某个参数变量选项改变的讨论,可能发现与之有关的,甚至能涉及模块间接口和系统结构参数的大问题。
2.3.2 静态分析¶
静态分析就是对系统的源代码进行研读,查找错误或收集一些度量数据,并不需要对代码进行编译和仿真运行。静态分析的查错和分析功能是其他方法所不能替代的,可以采用人工检测和计算机辅助静态分析手段进行检测,但越来越多地采用工具进行自动化分析。
从上述讨论可以知道,软件缺陷不仅存在于可执行的程序中,而且存在于需求定义和设计的文档之中,所以软件测试不仅 “是为了发现错误而执行程序的过程”, 而且还包括对产品规格说明书、技术设计文档等的评审 —— 静态测试。软件测试贯穿整个软件开发过程,是软件验证和用户需求确认的统一,和软件评审密不可分。
2.3.3 验证和确认¶
软件测试不仅要检查程序是否出错,程序是否和软件产品的设计规格说明书一致,而且还要检验所实现的功能是否就是客户或用户所需要的功能,这就引出软件测试中有名的 V&V。V&V, 即两个英文单词 Verification (验证) 和 Validation (有效性确认) 的第一个字母组合。软件测试可以看作针对软件产品 (包括阶段性成果、半产品) 的 “验证和有效性确认” 两类活动构成的统一体。正如第 1 章所说,这里的验证只局限于产品自身的验证。
1. 验证¶
Verification, 一般书上将它翻译为 “验证”, 但也可以翻译为 “检验”, 即检验软件是否已正确地实现了产品规格说明书所定义的系统功能和特性。验证过程提供证据表明软件相关产品与所有生命周期活动的要求 (如正确性、完整性、一致性和准确性等) 相一致,相当于,以软件产品设计规格说明书为标准进行软件测试的活动。
验证是否满足生命周期过程中的标准、实践和约定,验证为判断每一个生命周期活动是否已经完成,以及是否可以启动其他生命周期活动建立一个基准。
2. 有效性确认¶
Validation, 一般书上将它翻译为 “确认”, 但更准确的翻译应该是 “有效性确认”。这种有效性确认要求更高,要能保证所生产的软件可追溯到用户需求的一系列活动。确认过程提供证据表明软件是否真正满足客户的需求,一切从客户出发,理解客户的需求,对软件需求定义、设计的怀疑,发现需求定义和产品设计中的问题。这主要通过各种软件评审活动来实现,包括让客户参加评审、测试活动。
3. 两者的区别¶
为了更好地理解这两个单词的区别,可以概括地说,验证是检验开发出来的软件产品和设计规格说明书的一致性,即是否满足软件厂商的生产要求。但设计规格说明书本身就可能存在错误,所以即使软件产品中某个功能实现的结果和设计规格说明书完全一致,但可能并不是用户所需要的,因为设计规格说明书很可能一开始就对用户的某个需求理解错了,所以仅进行验证测试还是不充分的,还要进行确认测试。确认就是检验产品功能的有效性,即是否满足用户的真正需求。所以,BOEHM 是对 V&V 最著名又最简单的解释。
2.4 主动测试和被动测试¶
在软件测试中,比较常见的方法是主动测试方法,测试人员主动向被测试对象发送请求、或借助数据、事件驱动被测试对象的行为,从而验证被测试对象的反应或输出结果。在主动测试中,测试人员和被测试对象之间发生直接相互作用的关系,而且被测试对象完全受测试人员的控制,被测试对象处于测试状态,而不是实际工作状态,如图 2-9 (a) 所示。
在主动测试中,由于被测试对象受人为因素影响较大,而且一般是在测试环境中进行,不是在软件产品实际运行环境中进行,所以主动测试不适应产品在线测试。为了解决产品在线测试,被动测试方法应运而生。在被动测试方法中,软件产品运行在实际环境中,测试人员不干预产品的运行,而是被动地监控产品的运行,通过一定的被动机制来获得系统运行的数据,包括输入、输出数据,如图 2-9 (b) 所示。被动测试适合性能测试和在线监控,在嵌入式系统测试中,常常也采用被动测试方法。另外,大规模的复杂系统的性能测试,为了节省成本,可以采用这种方法。


在主动测试中,测试人员需要设计测试用例、尽力设法输入各种数据,而在被动测试中,系统运行过程中各种数据自然而然地产生了,测试人员不需要设计测试用例,只要设法获得系统运行的各种数据,但数据的完整性得不到保证。在被动测试中,关键建立监控程序 (代理), 并通过数据分析掌握系统的状态。
2.5 黑盒测试和白盒测试¶
从哲学观点看,分析问题和解决问题的方法有两种:白盒方法和黑盒方法。所谓白盒方法就是能够看清楚事物的内部,即了解事物的内部结构和运行机制,通过剖析事物的内部结构和运行机制,来处理和解决问题。如果没有办法或不去了解事物的内部结构和运行机制,而把整个事物看成一个整体 —— 黑盒子,通过分析事物的输入、输出以及周边条件来分析和处理问题,这种方法就是黑盒方法。软件测试具有相类似的哲学思想。根据是针对软件系统的内部结构、还是针对软件系统的外部表现行为来采取不同的测试方法,分别被称为白盒测试 (White-box Testing) 方法和黑盒测试 (Black-box Testing) 方法。这里的方法属于高层次的方法,归为方法论 (Methodology), 而第 3 章讨论的测试方法则是低层次的具体方法,也有一些文献 (如 SWEBOK) 将这些具体方法归为测试技术或测试技巧 (Technique)。
1. 白盒测试¶
白盒测试,也称结构化测试或逻辑驱动测试,也就是已知产品的内部工作过程,清楚最终生成软件产品的计算机程序结构及其语句,按照程序内部的结构测试程序,测试程序内部的变量状态、逻辑结构、运行路径等,检验程序中的每条通路是否都能按预定要求正确工作,检查程序内部动作或运行是否符合设计规格要求,所有内部成分是否按规定正常进行,如图 2-10 所示。
白盒测试不仅可以应用在程序的单元测试,覆盖程序的结构特性或逻辑路径,而且可以扩展到控制流路径、业务流程路径和数据流路径等的覆盖。一旦将这些流程图绘制出来,就可以设计足够的测试用例来覆盖其分支、条件、条件组合或基本路径等,从而比较容易衡量测试的覆盖率,以判断测试是否充分、是否达到相应的软件产品测试要求。白盒测试的基本原则如下。

白盒测试法试图穷举路径测试,但几乎不可能,因为贯穿一定规模的系统程序的独立路径数可能是一个天文数字。企图遍历所有的路径是很难做到的,即使每条路径都测试了,覆盖率达到 100%, 程序仍可能出错。
2. 黑盒测试¶
黑盒测试方法,也称数据驱动测试方法,在测试时,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,测试人员针对软件直接进行测试,如图 2-11 所示,检查系统功能是否按照需求规格说明书的规定正常使用、是否能适当地接收输入数据而输出正确的结果等,检查相应的文档是否采用了正确的模板、是否满足规范要求。

黑盒测试方法不关注软件内部结构,而是着眼于程序外部用户界面,关注软件的输入和输出,关注用户的需求,直接获得用户体验,从用户的角度或扮演用户角色来验证软件功能,验证产品每个功能是否都能正常使用,评估软件的使用质量。过去,人们常常把等价类划分法、边界值分析法、错误推测法等具体方法归为黑盒测试方法,不够恰当。例如,边界值分析方法,可以在系统外部输入中运用,也可以在代码内部变量测试中运用,前者归为黑盒测试方法,后者归为白盒测试方法。所以某种方法是否是黑盒测试方法,关键还是看是否是针对被测对象内部结构还是针对被测对象的整体来进行测试。黑盒测试方法常用于发现以下缺陷。
(6) 系统初始化问题等。¶
使用黑盒测试方法时,穷举测试也是不可能的,即不可能完成所有的输入条件及其组合的测试;黑盒测试法的覆盖率有时比较难以测定或达到一定水平时就难以提高,这是它的局限性。所以,在实际测试工作中,还要结合白盒测试方法,进行条件、逻辑和路径等方面的测试。
在实际工作中,可以根据需要,综合运用不同的测试方式、方法,以达到良好的测试效果。例如,将静态测试、动态测试和白盒测试、黑盒测试组合成 4 种基本的测试方式 (如表 2-1 所示), 以满足不同被测试对象的测试要求。
表 2-1 针对不同测试对象的 4 种基本组合的测试方法
| 白盒测试方法 | 黑盒测试方法 | |
| 静态测试方法 | 静态-白盒测试方法(对源程序代码的语法检查、扫描、评审等) | 静态-黑盒测试方法(对需求文档、需求规格说明书的审查活动,一些非技术性文档测试等) |
| 动态测试方法 | 动态-白盒测试方法(在单元测试中,一边运行代码,一边对结果进行检查、验证和调试等) | 动态-黑盒测试方法(在运行程序时,通过数据驱动对软件进行功能测试,从用户角度验证软件的各项功能) |
2.6 软件测试级别¶
软件测试贯穿软件产品开发的整个生命周期 —— 软件项目一开始,软件测试也就开始了,从产品的需求评审到最后的验收测试,不同的测试流程差别较大,但从测试层次来看,分为单元测试、集成测试、系统测试和验收测试,是基本的,即不管采用什么开发模型,这些层次的测试都是必要的。每个层次的测试最好是单独进行,只是在某些情况中,为了减少测试工作量或缩短开发周期,可以进行层次的合并,如单元测试和集成测试可以合并、系统测试和验收测试可以合并。
1. 单元测试¶
高可靠性的单元是组成可靠系统的坚实基础,单元测试在质量保证活动中举足轻重。单元测试是在编码阶段、针对每个程序单元而进行的测试,其测试的对象是程序系统中的最小单元 —— 类、函数、模块或组件等。单元测试主要使用白盒测试方法,从程序的内部结构出发设计测试用例,检查程序模块或组件已实现的功能与定义的功能是否一致,以及编码中是否存在错误。多个单元可以平行地、独立地被测试,通常要编写驱动程序和桩程序。
由于单元规模小、功能单一、逻辑简单,测试人员有可能通过技术设计文档、与开发人员交流和源程序等清楚地了解单元输入输出 (I/O) 条件和逻辑结构。采用白盒方法的结构化测试用例,然后辅以功能测试用例,使之对任何合理和不合理的输入都能鉴别和响应,从而能达到较为彻底的测试。
单元测试是测试执行的开始阶段,而且与程序设计和实现有非常紧密的关系,所以单元测试一般由编程人员和测试人员共同完成,编程人员一般起主导作用。在单元测试中,除了上述的 I/O 条件、程序逻辑结构、程序路径等实际测试手段之外,还会采取其他辅助手段,如代码走读 (Code Review)、静态分析 (Static Analysis) 和动态分析 (Dynamic Analysis) 等。
2. 集成测试¶
集成测试,也称组装测试、联合测试、子系统测试,是在单元测试的基础上,按照设计要求不断进行集成而进行的相应测试,目的是发现单元之间的接口问题,如接口参数类型不匹配、接口数据在传输中丢失、数据误差不断积累等问题。
选择什么样的方式把单元组装起来形成一个可运行的系统,直接影响到测试成本、测试计划、测试用例的设计、测试工具的选择等。通常有两种集成方式:一次性集成方式和渐增式集成方式,但一般要求采用渐增式集成方式。
3. 系统测试¶
系统功能测试应该在集成测试完成之后进行,而且是针对应用系统进行测试。功能测试是基于产品功能说明书、用户角度来对各项功能进行验证,以确认每个功能是否都能正常使用。在测试时,不考虑程序内部结构和实现方式,只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息,并且保持外部信息 (如数据库或文件) 的完整性。功能测试包括用户界面、各种操作、不同的数据输入输出和存储等的测试。
系统非功能性测试是实际运行环境 (包括软硬件平台、第三方支持软件、用户数据量等) 或模拟实际运行环境之上,针对系统的非功能特性所进行的测试,包括负载测试、性能测试、灾难恢复性测试、安全测试和可靠性测试等。
4. 验收测试¶
验收测试的目的是向未来的用户表明系统能够像预定要求那样工作,验证软件的功能和性能及其他特性是否与用户的要求一致。基于需求规格说明书和用户信息,验证软件的功能和性能及其他特性。验收测试,一般要求在实际的用户环境上进行,并和用户共同完成。
一个软件产品或互联网软件服务拥有众多用户,不可能由每个用户验收,此时采用称为 Alpha (α) 测试、Beta (β) 测试的过程。Alpha 测试是指软件开发公司内部人员开始试用新产品(称为 Alpha 版本),在实际运行环境和真实应用过程中发现测试阶段所没有发现的缺陷。经过 Alpha 测试和修正的软件产品称为 Beta 版本。紧随其后的 Beta 测试是指公司外部的典型用户试用,并要求用户报告异常情况、提出批评意见,然后再对 Beta 版本进行修正和完善,最终得到正式发布的版本。Beta 版本是比较常见的试用版本,在互联网应用系统中更为普遍。
2.7 软件测试计划和测试用例¶
就像软件过程分为基本工程过程和支持过程、管理过程,软件测试过程也可以分为工程过程和测试项目管理过程。从工程过程看,传统测试过程经过需求评审、设计评审、单元测试、集成测试、系统测试、验收测试;而从管理过程看,经过计划、设计和执行的过程,所以有必要了解测试计划和测试用例两个概念,其中测试用例是测试设计的主要产物。
2.7.1 测试计划¶
测试计划是为了高效地、高质量地完成测试任务而做的准备工作,包括对工作量的估算、测试资源和进度安排、测试风险评估、测试策略制定等工作。测试计划的基础是测试需求分析,基于明确的测试需求分析结果来确定测试范围和测试任务,才能估算测试工作量,得以进一步估算所需资源和时间,并最终制定测试计划书。
测试计划书的内容也可以按集成测试、系统测试、验收测试等阶段去组织。为每一个阶段制定一个计划书,还可以为每个测试任务 / 目的(安全性测试、性能测试、可靠性测试等)制定特别的计划书。测试计划是一个过程,不仅是 “测试计划书” 这样一个文档,测试计划会随着情况的变化不断进行调整,以便于优化资源和进度安排,减少风险,提高测试效率,并及时修改 “测试计划书”。测试计划书的主要内容集中在下列几个方面。
2.7.2 测试用例¶
测试用例 (Test Case) 是为了特定的测试目的 (如考察特定程序路径或验证某个产品特性) 而设计的测试条件、测试数据及与之相关的测试规程的一个特定的使用实例或场景。测试用例也可以被称为有效地发现软件缺陷的最小测试执行单元。而测试脚本 (Test Script) 是测试工具执行的一组指令集合,使计算机能自动完成测试用例的执行,也是计算机程序的一种形式。脚本可以通过录制测试的操作产生,也可以直接用脚本语言编写脚本。测试用例可以看作手工执行的脚本,而测试脚本可以看作是测试工具执行的测试用例。测试用例的主要作用有以下几方面。
两三次的回归测试。这些回归测试,就要求能重复使用测试用例。
(4)测试用例是一个知识积累的过程。在测试过程中,对产品特性的理解会越来越深,发现的缺陷也会越来越多。这些缺陷中,有些不是通过事先设计好的测试用例发现的,在对这些缺陷进行分析之后,需要加入新的测试用例,这就是知识积累的过程。即便最初的测试用例考虑不周全,随着测试的逐步深入下去,也将日趋完善。
测试用例是测试执行的基础,是根据相应的测试思路和测试方法设计出来的,所采用的各种测试设计方法会在第 3 章及其后续章节进行介绍,但测试用例的设计遵守一定的流程,例如下面的设计步骤就比较常见。
2.8 专业测试人员的责任和要求¶
虽然前面已经介绍了软件测试类型、测试层次、测试计划与设计,基本了解了测试工作,但还是不够,有必要进一步了解测试工作的主体 —— 专职的软件测试人员等。软件测试工作可以由开发人员,也可以由这个研发团队完成,但在目前业界现实状态来看,除了单元测试和集成测试,其他软件测试工作主要是专业测试人员完成,包括系统测试和验收测试,系统测试涉及不同的测试类型,如功能测试、性能测试、兼容性测试、安全性测试等。专业测试人员还要制定测试计划、设计测试用例、执行测试、评估测试结果、交付测试报告和进行缺陷分析等。
2.8.1 专业软件测试人员的责任¶
如果单从软件测试来看,软件测试团队是不能保证产品质量的,也就是说,产品的质量不是靠测出来的,而是靠产品开发的所有人员 (需求分析人员、系统设计人员、程序员、测试人员等) 共同努力来获得。专职测试人员的主要责任应该是:
(6) 对缺陷进行根本原因分析,抽象出缺陷模式,帮助团队做好缺陷预防;
(7) 帮助团队建立质量保证体系,如督促编程规范的建立和实施。
如果公司没有质量保证 (QA) 人员,专职测试人员的责任将从测试领域扩张到整个质量保证领域,这时测试人员拥有更多的责任,如增加下列责任。
(3)分析竞争对手的产品,了解自己产品设计的不足,提出改进的意见。
把软件测试和质量保证两项职能结合起来做,工作会更有效。软件测试为质量保证提供数据和质量评判的依据,质量保证可以指导软件测试的进行,将缺陷预防和事后检查有机结合起来,质量保证和软件测试相辅相成,达到良好的效果。
专业测试人员可以再细分一些角色,如软件测试工程师 (Software Test Engineer, STE)、测试软件开发工程师 (Software Development Engineer in Test, SDET)、自动化测试工程师、软件测试架构师 (Architect)、安全测试工程师、测试经理等。
2.8.2 对专业测试人员的要求¶
不少计算机软件业界人士认为,对软件测试人员要求比较低、容易招聘,认为他们只要会操作计算机、有一定的软件使用经验就可以了。他们认为,软件测试人员只要一步一步操作所要测试的软件,就能发现程序中的问题;或者依据软件产品规格设计说明书,通过和软件的实际表现进行对比就能够发现两者不一致的地方,发现缺陷,这些都不需要什么技术。
这种想法是错误的。测试工作的确是一项技术工作,不局限于功能测试,在进行集成测试和系统测试时,测试人员必须明白被测软件系统的实现原理、方法以及涉及的各种第三方平台、技术等内容。专职测试人员可能要进行数据库测试,这时需要数据库设计、开发和性能调优等能力;专职测试人员有时需要开发测试工具、或针对某测试工具开发测试脚本,这时需要良好的编程能力,而且拥有编程或开发经验的测试人员会对软件开发过程有更深的理解,对于开发人员、项目经理的沟通、测试工作改进等会有很大帮助。在进行性能测试、安全性测试、可靠性测试和兼容性测试等工作时,这就要求测试人员掌握系统架构设计、系统特性标识、系统环境设置等方面的知识。测试的方法也不能局限于黑盒测试方法,还需要结合白盒测试方法,这就要求测试人员具有一定的编程经验和系统架构知识。对软件测试人员的要求,不仅在技术上有较高要求,而且在沟通能力、理解能力、分析问题能力等方面的要求会更高。
示例:测试工程师的具体要求¶
2.8.3 优秀测试工程师应具备的素质¶
人是测试工作中最有价值也是最重要的资源,只有保证测试工程师良好的素质,才能保证测试、产品的质量。然而,在有些公司让那些没有应聘上开发职位的人来做测试,这绝对是错误的,最终会损害企业。
为高质高效地完成测试任务,软件测试工程师应具有很好的素质和能力,包括沟通能力、技术能力、自信心、耐心、怀疑一切的精神、勤奋精神、洞察力、适度的好奇心、反向思维和发散思维能力、记忆力等,甚至需要很好的幽默感、自我学习能力和创新能力。在招聘测试工程师时,着重考察应聘者是否具有这些良好的个人素质,保证所招聘的人符合测试人员的要求。
1. 责任感¶
测试人员需要高度的责任感,本着对质量一丝不苟的追求,坚持用客户的观点看待问题,不放过任何一个可能存在的疑点,充分关注细节。也只有具有高度的责任感,才能经受得住进度或其他方面来的压力,始终把质量放在第一。只有这样,才能保证测试工作的充分性和可靠性。
2. 沟通能力¶
测试工程师需要同软件开发过程中各种角色进行沟通,具有与技术 (开发者) 和非技术人员 (包括客户、市场人员和培训人员等) 的交流能力。既要可以和用户谈得来,又能同开发人员说得上话,但他们之间的沟通语言和方式有很大差别。和用户沟通的重点是系统要实现哪些功能、哪些功能是无关紧要的,尽量不使用专业术语。而和开发者交流时,则关心技术上的实现,常常使用专业术语。而且,也只有深入沟通,才能完整地理解用户的需求和待实现的产品特性,才能真正掌握产品设计和实现的技术细节。
由于测试工作本身是一个重要的任务,就是找出程序、系统中的缺陷,有些开发人员觉得是挑毛病,偶尔感到不高兴,这时和开发人员沟通,更需要技巧,这样才能将与开发人员之间可能发生的冲突和对抗减少到最低程度。测试人员应该把精力集中在查找错误上面,而不在于找出是哪个开发人员引入错误的,即测试的结果是针对产品,而不是针对编程人员,使用一种公正和公平的方式指出具体错误,对于测试工作是有益的。一般来说,武断地对产品进行攻击是错误的,采用一些外交方法就比较好。在遇到狡辩的情况下,一个幽默的批评将是很有帮助的。
3. 技术能力¶
软件测试归根结底还是技术性工作,归属于研发部门,技术是基础。如果没有技术,就只能进行黑盒的功能测试,有些测试任务就无法实现,某些时候测试效率比较低,个人的发展也会受到限制。有了良好技术,在早期就可以和开发人员一起讨论系统架构设计,验证系统是否具有可测性、发现单点失效、性能瓶颈等设计问题。有了良好技术,可以开发所需要的测试工具、自动化测试框架和自动化测试脚本等。技术能力,不局限于开发经验、编程能力,还应包括操作系统配置和排错(Troubleshooting)能力、网络技术等。
4. 自信心¶
开发人员指责测试人员出了错是常有的事,测试工程师对自己持有的正确观点应有足够的自信心,对自己所报的 Bug 应有信心。如果缺乏信心,很容易受开发人员的影响,测试工作缺乏独立性,程序中的漏洞或缺陷容易被忽略过去,导致软件产品质量的降低。
还有一种情况也是常见的,软件产品设计规格说明书总是或多或少存在一些逻辑问题,编程人员和测试人员对那些有问题的功能存在争议,这时候信心会帮助测试人员发现产品设计中的问题,说服产品设计人员。
5. 耐心¶
有些软件测试工作需要难以置信的耐心。有时需要花费大量的时间去分离、识别一个错误,需要对其中一个测试用例运行几十遍、甚至几百遍,了解错误在什么特别的情况下才发生。测试人员需要保持耐心,尤其是在集中注意力解决困难问题的时候,特别是在测试执行阶段,面对成百上千个测试用例,要一个个去执行,还要在不同的测试环境上重复,耐心是必要的。当然,应尽量让测试工具去完成那些重复性的任务。
6. 怀疑精神¶
可以预料,开发人员会尽自己最大的努力将所有的错误解释过去,测试人员在耐心听每个人解释的时候,还要保持高度警惕、怀疑一切,直到自己分析结果或亲自测试之后,才做出决定。有时,对一些功能的设计和实现自觉就是不对,可以持怀疑态度,看看是否有更好的实现方法,可以和产品设计人员、开发人员进行更深入的讨论。
7. 适度的好奇心¶
在开发测试用例时使用的方法,有点像勘探专家在一个山洞中摸索前进的方法一样。虽然周围可能存在大量的死胡同,但是测试工程师具有适度的好奇心,会促使他们向山洞中的深处探索,探索没有去过的地方,最终可能会有一个大发现。
设计出那些导致系统边界出错的测试用例,往往需要一定的好奇心。测试工程师在审查规格说明书时,可以与开发人员一起讨论各种 “假设” 的场景,并在大脑中反复演练被测试系统,以找到可能出现的例外或边界问题。测试人员善于从不同的角度来进行探索性测试,包括采用错误猜测法,设计一些试图破坏系统的测试用例。如果测试人员缺乏好奇心,那么只能设计出肤浅的测试用例。
如果测试人员在一个错误上花费太多时间,通过无数的尝试去分析造成这种错误的根本原因,这样做也是不正确的,好奇心需要适度。在及时完成测试执行任务和编写灵活高效的测试用例之间,在进度的压力和探究错误发生根源之间,优秀的测试人员能够取得平衡。怀疑精神和好奇心也有一定的联系,比较相似,也需要适度,不能 “杞人忧天”。
8. 洞察力¶
具有适度的怀疑精神和好奇心,如果缺乏洞察力,测试能力还会受到较大的限制。一个好的测试工程师具有一种先天的敏感性,并且能尝试着通过一些巧妙的变化去发现问题。例如,测试人员能够捕获用户使用系统的一些特定场景,发现一些隐藏较深的严重缺陷。如果能够洞察开发人员的弱点或系统的薄弱环节,对更快地发现问题也会有很大帮助。有了良好的洞察力,也有助于识别测试的风险,从而降低测试的风险,确保测试项目的成功。
9. 反向思维和发散思维能力¶
测试工程师应想尽办法来考虑产品可能出现失败的各种方式,最大限度地暴露其存在的问题、用严格的边界条件来检验它,让系统经受压力测试,或者是强迫它处理 “不可能发生的” 错误。所有这样的负面测试,都需要反向思维和良好的发散思维能力。
10. 记忆力¶
如果测试工程人员有能力将以前曾经遇到过的类似的错误从记忆深处挖掘出来,这对以后的测试有很大帮助,因为不少错误是由于开发人员的不良习惯导致的。在测试一个产品的新版本时,如果清楚已发布的各种版本的产品功能,就比较容易了解新版本的功能做了哪些改动、为什么改、怎样改了之后会对其他特性有哪些影响等一系列问题。如果熟悉软件各种老版本所出现的缺陷,有助于对新版本的用例设计和测试执行。
小结¶
软件测试是软件质量保证的手段,软件测试基于两个最基本的概念来展开,这两个基本概念就是质量和客户。软件质量就是客户的满意度,而测试就是时时刻刻从客户的角度出发,验证软件产品是否满足客户的实际需求。软件产品的质量的不仅包含功能性需求,而且包含非功能性需求,如适用性、功能性、有效性、可靠性和性能等。
软件测试的主要目的之一就是尽快尽早地发现软件缺陷,而软件缺陷是由软件本身、团队工作和技术问题等多方面因素引起的,而且集中在需求分析、系统设计这两个阶段,代码的错误要比需求分析书、设计规格说明书所存在的问题要少。
软件测试可以根据测试的层次、被测试对象、测试目标、测试过程等进行分类,通过分类可以全面地了解测试的概貌和内容。软件测试除了工程过程之外,还要经历测试计划、设计测试、执行测试、评估测试结果等类似于项目的实施过程。
在传统的软件开发模式下,软件测试作为一个团队存在,有更多的角色,如测试工程师、自动化测试工程师、测试组长、测试经理等。在敏捷开发模式中,可能不存在测试团队,但专职的测试人员还是存在的,有些测试角色的名字可能也需要变一变,例如,测试组长可以改为 Test Owner 而存在下来,而且对专业的测试人员的要求没有变化,要求测试人员具有良好的沟通能力、技术能力、思考能力,还应具备良好的素质,包括幽默感、耐心、怀疑精神、适度的好奇心等。
思考题¶
-
如何看待软件测试在保证软件产品质量中所起的作用?
-
如何理解软件质量和软件缺陷的对立统一关系?
-
从修复软件缺陷的代价来讨论测试为什么要尽早开始。
-
结合测试目标来分析测试工作的各项主要内容。
-
需求分析、系统设计所存在的问题在软件缺陷中占有较大比例,对软件开发和测试工作有何启发?
-
通过与业界的测试工程师交流,了解他们的感受以及对未来将要从事测试工作的大学生有什么具体的建议。