软件测试程序设计技术(txt+pdf+epub+mobi电子书下载)


发布时间:2020-10-11 00:40:57

点击下载

作者:孙晶,杨波

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

软件测试程序设计技术

软件测试程序设计技术试读:

前言

计算机技术已经越来越广泛地应用于国民经济和国防建设的各个部门,以不可阻挡之势渗透到人们工作和生活的各个领域,尤其在航天、航空、核能、通信、交通、金融等一些关键领域中,计算机的作用更加至关重要。同时,它们对计算机软件的可靠性和安全性也有严格的要求。近年来,由于软件错误而造成经济损失、导致严重后果的事件屡见不鲜,因此,如何保证软件产品的质量和可靠性就成为人们必须解决的一个重要问题,而软件测试便是保证软件质量的一个重要手段。据统计,国外在软件开发中,开发费用的近一半甚至更多要用于软件测试,由此也可以看出软件测试在软件开发中的重要地位。

本书是为希望了解软件测试的相关技术,尤其是希望了解TTCN-3的读者而编写的。依托TTCN-3,本书给出了丰富且易于实践的案例,让读者能够做到理论与实践相结合,从而能够更加充分地理解和掌握软件测试的相关方法和技术。

本书共10章,第1章是软件测试概述,第2章是软件测试基础,第3章是TTCN树表描述语言程序设计,第4章是TTCN-3基本语言元素,第5章是类型声明,第6章是语句、函数、可选步与通信,第7章是TTCN-3核心语言程序设计,第8章是测试描述与测试控制,第9章是系统测试及测试工具,第10章是基于TTCN-3的软件测试案例。

本书主要介绍如下内容。(1)介绍软件测试的基本方法,重点讨论软件测试黑盒法和白盒法。对软件测试的过程进行讨论,重点讨论软件测试的设计和测试文档的使用。(2)介绍TTCN-3核心语言的基本概念、语法结构和测试系统结构。通过学习可以掌握TTCN-3核心语言测试系统的设计与实现方法,能够设计小型协议软件、应用软件、嵌入式软件的测试系统,为实际从事测试工作奠定理论基础。(3)介绍如何利用TTCN-3进行实际的软件测试,结合多个测试案例进行详细的讲解。

本书详细地讲述了软件测试的有关概念、方法、过程等方面的基础知识,也用大量篇幅讲解了TTCN-3的语法知识,并给出了丰富的案例,目的是使读者对软件测试有一个比较全面的了解,并为进一步研究软件测试技术奠定基础。

本书中有大量的算法语句、程序语句及计算公式等,对于其中的变量,为了方便读者阅读,避免歧义,不再区分正、斜体,而是统一采用正体,特此说明。

本书由孙晶、杨波主编,赵会群主审。

由于编者水平有限,书中难免有疏漏和不当之处,敬请广大读者不吝指正。作者

第1章 软件测试概述

本章概述软件测试的有关概念、方法和过程等方面的基础知识。使读者对软件测试有一个比较全面的了解,并为进一步讨论软件测试技术奠定基础。

1.1 软件故障与软件测试

在计算机故障中,有相当一部分是软件故障。下面让我们看两个例子。

例1:英特尔奔腾浮点除法软件故障

在计算机的“计算器”程序中输入以下算式:

如果答案是0,则说明计算机没有问题;如果得出的结果不是0,则说明计算机的工作不正常。看起来这不应该是个问题,可实际上就出现了问题。

1994年12月30日,美国Lynchburg大学的Thomas R.Nicely博士在一台奔腾PC上做除法运算时发现,上面的算式不等于0。后来,他把这一个惊人的发现在Internet上发布出去,引起了一场风暴,成千上万的人都发现了同样的问题。那么是什么原因造成这样的算式计算错误呢?这由固化在奔腾CPU上的运算器芯片中的软件故障所致。

例2:千年虫(Y2K)问题

首先介绍一个传说:20世纪70年代一个名叫Dave的程序员,负责其公司的工资系统。他使用的计算机存储空间很小,迫使其尽量节省每一个字节。Dave自豪地将自己的程序压缩得比其他人的更小。他使用的其中一个方法是把4位数日期缩减为2位,例如将1973年缩为73。因为工资系统极度依赖数据处理,Dave节省了可观的存储空间。Dave并没有想到这是个很大的问题,他认为只有在2000年时程序计算00或01这样的年份时才会出现错误。他知道那时会出问题,但是在25年之内程序肯定会更改或升级,而且眼前的任务比未来更加重要。这一天毕竟是要来到的。1995年,Dave的程序仍然在使用,而Dave退休了,谁也不会想到进入程序检查2000年的兼容性问题,更不用说去修改了。

关于Y2K问题的说法不一,但根本的问题是用2位表示年份的问题。这是一个十分典型的软件设计缺陷。Y2K问题涉及4个方面:硬件、操作系统、应用软件及数据。

有关千年的例子很多,给计算机产业带来一次震惊和恐慌。许多国家和大型计算机公司都动用了大量的人力和物力,解决千年虫问题,尤其是解决关系到国家安全、国家支柱产业正常运转和与百姓生活息息相关领域的计算机系统的千年虫问题。

微软作为全球最大的软件供应商,其产品涵盖了操作系统、应用软件及数据等领域,而在PC平台上形成最为广泛的应用。关于这一问题,微软对其产品进行了全面的兼容性测试。

微软自1996年起开始涉及有关Y2K问题的研究,对此,微软采取的是完全对外公开的策略,其中包括产品及其他任何有关Y2K的信息。作为一家既面向企业用户也针对广大个人用户的软件产品供应商,微软认为解决Y2K的首要问题是对产品进行全面深入的2000年兼容性测试。

首先,需要找到一种统一的方法来对不同的产品进行2000年兼容性测试;同时,由于微软的产品在全球得到了极为广泛的应用,因此要对产品进行不同语言的测试。至1999年年底,微软共测试了4052种产品,这可谓迄今为止历史上最大的软件测试工程之一;其中,97%达到2000年兼容,3%不兼容。而不兼容的产品基本都是老产品,如DOS版本的Word 5.0。同时,在整个测试过程中,并未做任何推断性测试,即不能在未对某种语言进行实际性测试的前提下,而从其他语言的同种产品的测试结果进行推断(如假设简体中文的测试结果没问题,则简单推断韩文也不存在任何问题)。英文及其他欧洲语言中只有5%,而20%以上的双字节语言(如大多数亚洲国家的语言)采用UNICODE;同时,世界各地不同的民族采用不同的历法,这些都是测试需要考虑的问题。测试时尽力确保最新产品和最大量使用的产品以及采用关键技术,如ODBC的产品的2000年兼容测试,然后再来测试客户有特别需求的、采用某项专有技术的产品。

从上面的两个例子中,我们可以看出软件缺陷是造成软件故障的主要问题,也是软件测试的主要对象。那么什么是软件缺陷故障?什么是软件故障?软件测试定义是什么?它们之间的关系是什么?下面先给出一组有关软件测试的相关术语,明确它们之间的关系,进而给出软件测试的概念。

缺陷(bug)

偏差(variance)

缺点(defect)

失败(failure)

问题(problem)

矛盾(inconsistency)

错误(error)

事故(incident)

异常(anomaly)

谬误(fault)

在上述名词中,有一些名词的含义相近,属于一个范畴。第一类是缺陷、缺点和偏差,它们是一类含义相近的概念,我们不妨把它们统称为缺陷。它们都是软件开发过程潜在的缺陷,这些缺陷可能在软件投入运行后出现,使得软件的性能和可靠性等方面与系统的设计需求不符。有时,这些问题可能不出现,软件的性能和可靠性并不会因为它们的存在而受到影响。第二类是错误、谬误、问题、异常和矛盾等,我们把这一类问题统称为错误。这类错误与软件运行状态有关,它们是在软件运行过程中可观测到的软件错误。这些问题出现的原因是软件缺陷所致。第三类是失败、事故或灾难等,我们把这类统称为失败。这是软件运行给用户造成的损失的一类软件故障,它强调软件失败的结果。失败的直接原因是软件系统存在软件错误。并不是所有的软件错误都会导致软件失败,如果对软件错误加以适当的控制,软件错误可以导致安全。

综上所述,软件故障大体上可分为三种类型,每一类对应软件生命周期的不同阶段,贯穿整个软件开发和使用的全部过程。其中,第一类缺陷是软件故障的根源,后两类故障是软件缺陷的直接后果。所以,在软件开发过程中,发现和排除软件故障是一项长期艰苦的工作。而这一项工作的基础是加强软件设计时设计缺陷的检测。

那么什么是软件测试呢?所谓软件测试是为了评价一个软件系统的质量和发现错误而从事的一种工作过程。从软件测试作为软件的执行过程来看,可分为局部软件的局部运行和全部运行;从运行的环境来看,可有仿真运行和实际运行。这就存在一个软件测试中的方式和方法的问题。而方法又与采用的技术相关,技术不同,方法也不同。所以,软件测试技术是测试的关键。

从软件故障的分类中,可以看到软件的故障分布在软件开发的全过程,所以软件测试也就伴随软件开发和使用的整个过程中。在下一节中,我们将分析软件测试与软件生命周期的关系。把握软件测试与开发过程的阶段关系,为有针对性地开展软件测试奠定基础。

1.2 软件测试与软件开发过程

软件开发过程中的各种活动构成软件开发的生命周期,随着这些活动的组织方式和方法不同,就构成不同的软件开发生命周期模型。然而,无论是什么样的生命周期模型,软件开发无一例外地要经历从软件需求分析到软件测试这样一个过程。也就是说,虽然软件开发的生命周期模型有所不同,但软件开发的阶段性始点和终点是相同的,而且软件测试是不可缺少的一项工作。

软件开发的生命周期并不是独立存在的,它是包含该软件的产品生命周期的一部分。在产品的生命周期内,软件被维护和纠错。当产品就是软件本身时,软件的维护和测试也是相当复杂的一项工作。不同的软件模块被组合成一个大的软件系统,给软件测试工作带来一定的难度。

有许多不同的软件生命周期模型,它们都需要进行测试。本节讨论各种软件开发生命周期模型与软件测试的关系,从而进一步明确软件测试在软件开发中的重要作用;为在采用不同软件开发方法的情况下,灵活运用软件测试的方法和技术奠定基础。1.2.1 顺序生命周期模型(Sequential Lifecycle Models)

所谓的顺序生命周期模型(简称顺序模型),是指把软件开发的整个过程定义成有序的开发活动序列,随着开发工作的进展,软件生命周期的状态也在迁移。如图1-1、图1-2所示,顺序模型也称V模型或瀑布模型。图1-1 顺序生命周期模型图1-2 瀑布生命周期模型

瀑布模型也有许多变形,这些模型可能随着软件开发需求的不同,增加新的状态,这些状态有着不同的边界,下面给出一组典型的开发状态描述。

●需求阶段(Requirements Phase):在需求阶段需要对用户需求进行分析,对要开发的软件进行严格的定义,这种定义应该是非二义性的。

●体系结构设计阶段(Architectural Design Phase):在该阶段对软件系统的体系结构进行分析、设计和定义,进而说明体系结构中组件和组件之间的联系。

●系统详细设计阶段(Detailed Design Phase):在该阶段对构成系统的各组件给出详细的设计和说明。

●编码和单元测试阶段(Code and Unit Test Phase):该阶段对设计的组件进行编码,并验证组件代码与详细设计阶段定义的组件细节的正确性。

●软件集成阶段(Software Integration Phase):在该阶段把已经测试过的组件组装到一起,并对集成系统进行测试,直到由组件所构成的软件满足设计要求。

●系统集成阶段(System Integration Phase):在该阶段对软件与其他系统部件进行集成,并进行系统测试,直到系统正常工作为止。

●验收测试阶段(Acceptance Test Phase):在该阶段将按照系统分析、设计定义的各个方法对系统进行测试,从而检验系统开发的正确性。

在上述系统生命周期中,前三个阶段是系统的定义阶段,后面四个阶段都需要对阶段成果进行测试。测试工作同样需要设计和说明,在生命周期的各个层面中,均需要定义该层面的测试点。1.2.2 渐进(Progressive Development)生命周期模型

顺序生命周期模型是一个理性化的软件开发生命周期模型。在实际开发过程中,可能情况要复杂得多。这样根据特殊情况设计具体的软件开发生命周期模型是常见的。比如软件需求往往随着开发工作的进行而不断地扩充,或者为了避免开发周期过长,而先开发一个中间系统投入运行等,这些特殊情况改变了原有生命周期的各个阶段的分配。

下面介绍另一个软件开发生命周期模型,这个模型称为渐进生命周期模型(如图1-3所示)或阶段生命周期模型。图1-3 渐进生命周期模型

软件开发过程中的一个矛盾是,开发时间过长,而工期又往往要求很短。解决此问题的一个方法是在两者之间折中处理,首先用较短的时间开发一个中间系统,而功能相对比设计要求少一些。这个中间系统还需要进一步扩展,直到满足所有的功能需求。中间软件的开发可以有效地减少软件开发风险。我们把这种开发方法所建立的软件开发生命周期称为渐进生命周期模型(简称渐进模型)或阶段实现(Phased Implementation)生命周期模型。

在渐进模型中,每一个开发阶段仍然服从顺序模型中的规范,而整个生命周期的阶段可能有所增减,它的实际阶段取决于实际开发过程。

每一个提交的软件都要经过测试,以检验软件是否满足设计要求。测试工作分布在软件开发的各个阶段,不但要对各个阶段的成果进行测试,而且还要对各个阶段的集成成果进行检验。如果这种测试工作能够在控制范围内完成,则该工作将不会影响整个生命周期。然而,测试中发现的问题是严重的,有时需要重新开发软件。这是最坏的情况,但在这种情况下,整个软件的生命周期都将被打乱。无论是哪种情况,测试都需要花费很多时间和精力。所以我们应该尽可能及早地发现问题,减少不必要的开发代价。其中一个解决办法就是利用原型法构造系统的原型。系统的原型是提供快速实现系统设计功能的方法,开发人员和用户可以在系统原型上测试所开发的系统是否满足设计要求。一个原型系统最终要进一步扩展成一个实际的系统,但在从原型系统到实际系统的过渡过程中,仍然需要测试。1.2.3 迭代生命周期模型(Iterative Lifecycle Model)

在迭代生命周期模型中,开发工作的最初并不要求对软件需求进行详细的说明,而是随着软件开发工作的进行,逐渐辨别所开发软件的需求,并加以说明。上述过程可能要重复多次,产生新的软件版本。迭代模型就是这样一种开发模型,其生命周期表现为四个不断迭代的阶段,如图1-4所示。图1-4 迭代生命周期模型

●需求分析阶段:该阶段对软件的需求进行收集并分析。在此基础上,不断的迭代将会得到最终的需求定义。

●设计阶段:该阶段根据需求进行设计,设计可能是新的设计,也可能是对早期设计的扩展。●编程与测试阶段:该阶段的中心任务是对软件进行编码、集成和测试。

●评审阶段:在该阶段要对软件进行评估,回顾软件的需求,改变或增加新的需求。

对迭代中的每一个周期循环,必须决定软件中哪些部分或全部组件需要在下一次周期循环中被保留,或是被摒弃掉。最终将达到一个目标就是软件需求被满足,这时软件被提交。或者该软件不可能达到设计要求,而不得不从头开始。

迭代模型可以形象地比喻为通过连续的逼近方法来开发软件。这有一些像数学中的逼近法,它通过不断的逼近最终使问题求解。然而,在数学中逼近有时没有解,每一次迭代都在可行解的左右摆动,甚至是发散的。迭代的次数可能会很大,甚至是不可能的。那么在软件开发中,是不是这样呢?情况十分相似。软件中的错误会使得软件生命周期没有尽头,这也是一种发散。

在迭代模型中,成功的关键是在周期内的每一个阶段和循环中都要对结果进行严格的测试。模型的前三个阶段是顺序模型的浓缩,每一个循环中都要对软件进行单元测试,随着生命周期的延续,测试形影不离。

1.3 软件测试方法与测试内容

软件测试的种类很多,大体上可以从以下几个方面来进行划分。

● 从是否需要执行被测软件的角度,可分为静态测试和动态测试。

● 从测试是否针对系统的内部结构和具体实现算法的角度,可分为白盒测试和黑盒测试。

● 从测试范围角度,可分为单元测试、系统测试、集成测试等。

● 从测试目标角度,可分为性能测试、功能测试、可靠性测试等。

● 从测试采用的工具角度,可分自动测试和手工测试等。

软件测试的种类多种多样,测试所采用的测试的方法和技术也是多种多样的。有些测试方法是针对测试对象提出的,有些测试方法是根据测试软件的组织结构而提出的,而有些是从测试工具角度提出的。但无论是哪种方法,其核心都是比较设计需求与软件的实际执行结果的一致性、兼容性。

下面逐一介绍目前我们所听到的各种软件测试方法,通过这些方法的介绍了解软件测试的测试内容。1.3.1 黑盒测试

黑盒测试也称功能测试或数据驱动测试,它是在已知产品所应具有的功能的情况下,通过测试来检测每个功能是否都能正常使用。在测试时,把程序看成一个不能打开的黑盆子,在完全不考虑程序内部结构和内部特性的情况下,测试者在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确地输出信息,并且保持外部信息(如数据库或文件)的完整性。黑盒测试方法主要有等价类划分、边值分析、因—果图、错误推测等,主要用于软件确认测试。“黑盒”法着眼于程序外部结构、不考虑内部逻辑结构、针对软件界面和软件功能进行测试。“黑盒”法是穷举输入测试,只有把所有可能的输入都作为测试情况使用,才能以这种方法查出程序中所有的错误。实际上测试情况有无穷多个,人们不仅要测试所有合法的输入,而且还要对那些不合法但是可能的输入进行测试。1.3.2 白盒测试

白盒测试也称结构测试或逻辑驱动测试,它是在知道它产品内部工作过程的前提下,可通过测试来检测产品内部动作是否按照规格说明书的规定正常进行。按照程序内部的结构测试程序,检验程序中的每条通路是否都有能按预定要求正确工作,而不顾它的功能,白盒测试的主要方法有逻辑驱动、基路测试等,主要用于软件验证。“白盒”法要求全面了解程序内部逻辑结构、对所有逻辑路径进行测试。“白盒”法是穷举路径测试。在使用这一方案时,测试者必须从检查程序的逻辑着手,检查程序的内部结构,得出测试数据。而贯穿程序的独立路径数是天文数字。但由于下面的原因即使每条路径都测试过,仍然可能存在错误。第一,穷举路径测试决不能查出程序违反了设计规范,即程序本身是个错误的程序。第二,穷举路径测试不可能查出程序中因遗漏路径而出现错误。第三,穷举路径测试可能发现不了一些与数据相关的错误。1.3.3 ALAC(Act-like-a-customer)测试

ALAC测试是一种基于客户使用产品的知识开发出来的测试方法。ALAC测试是基于复杂的软件产品有许多错误的原则。最大的受益者是用户,缺陷查找和改正将针对哪些客户最容易遇到的错误。1.3.4 单元测试

单元测试的对象是软件设计的最小单位——模块。单元测试的依据是详细设计描述,单元测试应对模块内所有重要的控制路径设计测试用例,以便发现模块内部的错误。单元测试多采用白盒测试技术,系统内多个模块可以并行地进行测试。1.3.5 综合测试

时常有这样的情况发生:每个模块都能单独工作,但这些模块集成在一起之后却不能正常工作。发生这种情况的主要原因是,模块相互调用时接口会引入许多新问题。例如,数据经过接口可能丢失、一个模块对另一模块可能造成不应有的影响、几个子功能组合起来不能实现主功能、误差不断积累达到不可接受的程度以及全局数据结构出现错误,等等。综合测试是组装软件的系统测试技术,按设计要求把通过单元测试的各个模块组装在一起之后,进行综合测试以便发现与接口有关的各种错误。1.3.6 确认测试

通过综合测试之后,软件已完全组装起来,接口方面的错误也已排除,软件测试的最后一步——确认测试即可开始。确认测试应检查软件能否按合同要求进行工作,即是否满足软件需求说明书中的确认标准。

1.确认测试标准

实现软件确认要通过一系列黑盒测试。确认测试同样需要制订测试计划和过程,测试计划应规定测试的种类和测试进度,测试过程则定义一些特殊的测试用例,旨在说明软件与需求是否一致。无论是计划还是过程,都应该着重考虑软件是否满足合同规定的所有功能和性能,文档资料是否完整、准确人机界面和其他方面(例如可移植性、兼容性、错误恢复能力和可维护性等)是否令用户满意。

确认测试的结果有两种可能:一种是功能和性能指标满足软件需求说明的要求,用户可以接受;另一种是软件不满足软件需求说明的要求,用户无法接受。项目进行到这个阶段才发现严重错误和偏差一般很难在预定的工期内改正,因此必须与用户协商,寻求一个妥善解决问题的方法。

2.配置复审

确认测试的另一个重要环节是配置复审。复审的目的在于保证软件配置齐全、分类有序,并且包括软件维护所必需的细节。1.3.7 α、β测试

事实上,软件开发人员不可能完全预见用户实际使用程序的情况。例如,用户可能错误地理解命令,或提供一些奇怪的数据组合,也可能对设计者自认明了的输出信息迷惑不解,等等。因此,软件是否真正满足最终用户的要求,应由用户进行一系列验收测试。验收测试既可以是非正式的测试,也可以是有计划、系统的测试。有时,验收测试长达数周甚至数月,不断暴露错误,导致开发延期。一个软件产品,可能拥有众多用户,不可能由每个用户验收,此时多采用称为α、β测试的过程,以期发现那些似乎只有最终用户才能发现的问题。

α测试是指软件开发公司组织内部人员模拟各类用户对即将面市软件产品(称为α版本)进行测试,试图发现错误并修正。α测试的关键在于尽可能逼真地模拟实际运行环境和用户对软件产品的操作并尽最大努力涵盖所有可能的用户操作方式。经过α测试调整的软件产品称为β版本。紧随其后的β测试是指软件开发公司组织各方面的典型用户在日常工作中实际使用β版本,并要求用户报告异常情况、提出批评意见。然后,软件开发公司再对β版本进行改错和完善。1.3.8 系统测试

计算机软件是基于计算机系统的一个重要组成部分,软件开发完毕后会与系统中其他成分集成在一起,此时需要进行一系列系统集成和确认测试。对这些测试的详细讨论已超出软件测试的范围,这些测试也不可能仅由软件开发人员完成。在系统测试之前,软件工程师应完成下列工作。(1)为测试软件系统的输入信息设计出错处理。(2)设计测试用例,模拟错误数据和软件界面可能发生的错误,记录测试结果,为系统测试提供经验和帮助。(3)参与系统测试的规划和设计,保证软件测试的合理性。

系统测试应该由若干个不同测试组成,目的是充分运行系统,验证系统各部件是否都能正常工作并完成所赋予的任务。系统测试中又包括恢复测试、安全测试、强度测试、性能测试、可用性测试、可靠性测试。(1)恢复测试:恢复测试主要检查系统的容错能力,即当系统出错时,能否在指定时间间隔内修正错误并重新启动系统。恢复测试首先要采用各种办法强迫系统失败,然后验证系统是否能尽快恢复。对于自动恢复需验证重新初始化(Reinitialization)、检查点(Checkpointing Mechanisms)、数据恢复(Data Recovery)和重新启动等机制的正确性;对于人工干预的恢复系统,还需估测平均修复时间,确定其是否在可接受的范围内。(2)安全测试:安全测试检查系统对非法侵入的防范能力。安全测试期间,测试人员假扮非法入侵者,采用各种办法试图突破防线。例如,①想方设法截取或破译口令;②专门定做软件破坏系统的保护机制;③故意导致系统失败,企图趁恢复之机非法进入;④试图通过浏览非保密数据,推导所需信息,等等。理论上讲,只要有足够的时间和资源,没有不可进入的系统。因此系统安全设计的准则是,使非法侵入的代价超过被保护信息的价值。此时,非法侵入者已无利可图。(3)强度测试:强度测试检查程序对异常情况的抵抗能力。强度测试总是迫使系统在异常的资源配置下运行。例如,①当中断的正常频率为1~2h/s,运行每秒产生10个中断的测试用例;②定量地增加数据输入率,检查输入子功能的反应能力;③运行需要最大存储空间(或其他资源)的测试用例;④运行可能导致虚存操作系统崩溃或磁盘数据剧烈抖动的测试用例,等等。(4)性能测试:对于那些实时和嵌入式系统,软件部分即使满足功能要求,也未必能够满足性能要求,虽然从单元测试起,每一测试步骤都包含性能测试,但只有当系统真正集成之后,在真实环境中才能全面、可靠地测试运行性能,系统性能测试是为了完成这一测试任务的。性能测试有时与强度测试相结合,经常需要其他软硬件的配套支持。(5)可用性测试:对“用户友好性”的测试。显然这是主观的,且将取决于目标最终用户或客户。用户面谈、调查、用户对话的录像和其他一些技术都可使用。程序员和测试员通常都不宜作为可用性测试员。(6)可靠性测试:可靠性测试是为了检验系统软件系统运行是否可靠而进行的一种测试。这类软件系统的失败往往导致不可预料的结果,如航空、航天领域中运行的软件,铁路系统中运行的软件等。可靠性测试的方法关注的是,一旦软件系统出现故障,其系统是否导向安全,所以可靠性测试与安全测试紧密相关。可靠性测试通常采用黑盒测试法。1.3.9 面向对象的软件测试

面向对象的软件测试(OO Test)是根据面向对象的软件开发方法所设计的软件系统所提出的软件测试方法。OO Test又分为面向对象分析的测试(OOA Test)、面向对象设计的测试(OOD Test)和面向对象的程序测试(OOP Test)。它们是对分析结果和设计结果的测试,主要是对分析设计产生的文本进行,是软件开发前期的关键性测试。OOP Test主要针对编程风格和程序代码实现进行测试,其主要的测试内容在面向对象单元测试和面向对象集成测试中体现。面向对象单元测试是对程序内部具体单一的功能模块的测试,如果程序是用C++语言实现,主要就是对类成员函数的测试。面向对象单元测试是进行面向对象集成测试的基础。面向对象集成测试主要对系统内部的相互服务进行测试,如成员函数间的相互作用、类间的消息传递等。面向对象集成测试不但要基于面向对象单元测试,更要参见OOD或OOD Test结果。面向对象系统测试是基于面向对象集成测试的最后阶段的测试,主要以用户需求为测试标准,需要借鉴OOA或OOA Test结果。1.3.10 协议软件测试

在计算机网络的发展历程中,协议一直处于核心地位,它是计算机网络和分布式系统中各种通信实体之间相互交换信息所必须遵守的一组规则。1984年,国际标准化组织ISO提出了开放式系统互连ISO/OSI参考模型。1993年1月1日,TCP/IP被宣布为Internet上唯一正式的协议,为Internet的发展铺平了道路。

协议软件作为软件的一种特殊形式,自20世纪80年代以来,其开发和检测方法已经得到快速的发展,已经形成了一个崭新的学科——协议工程学。它的研究范围包括协议说明(Protocol Specification)、协议证实(Protocol Validation)、协议验证(Protocol Verification)、协议综合(Protocol Synthesis)、协议转换(Protocol Conversion)、协议性能分析(Protocol Performance Analysis)、协议自动实现(Protocol Automatic Implementation)和协议测试(Protocol Testing)。

目前的网络协议多是以自然语言描述的文本,实现者对于协议文本的不同理解以及实现过程中的非形式化因素都会导致不同的协议实现,有时甚至是错误的协议实现。即便协议实现正确,也不能保证不同的实现彼此之间能够准确无误地通信,而且同一协议的不同实现其性能也有差别。在这种情况下,需要一种有效的方法对协议实现进行评价,这就是“协议测试”。

伴随着计算机网络的普及和网络需求的增多,计算机网络协议越来越复杂庞大,协议实现不仅仅要求功能正确完善、能够互通,而且要求具有良好的性能,因此协议的实现和开发越来越复杂。为了保证质量,协议测试是一个必需且十分重要的手段。目前的协议测试已经不仅仅是产品开发研制过程中一个简单的检测支持过程,而是发展成为计算机网络技术的一个重要分支。对协议测试技术的研究将直接影响到计算机网络技术的进步和世界网络市场的竞争与发展。所以,很多国家都投入了大量的人力、物力从事协议测试的研究工作,例如英国的国家物理实验室NPL、法国国家通信研究中心、德国国家通信研究局GMD、美国国家标准化研究局、美国新罕布什尔大学互操作研究实验室、中国清华大学计算机科学与技术系的计算机网络与协议测试实验室等单位都在这个领域投入了大量的研究力量。

协议测试是在软件测试的基础上发展起来的。根据对被测软件的控制观察方式,软件测试方法分为三种:白盒测试、黑盒测试和灰盒测试。协议测试是一种黑盒测试,它按照协议标准,通过控制观察被测协议实现的外部行为对其进行评价。目前,协议测试分成三个方面进行研究:一致性测试(Conformance Testing)、互操作性测试(Interoperability Testing)和性能测试(Performance Testing)。一致性测试主要测试协议实现是否严格遵循相应的协议描述;互操作性测试关注的是对于同一个协议标准,不同协议实现之间的连通问题。性能测试是用实验的方法来观测被测协议实现的各种性能参数,如吞吐量和传输延迟等,其结果往往与输入负载有关。

在上述三个方面,一致性测试开展最早,也形成了很多有价值的成果。1991年,国际标准化组织ISO制定的国际标准ISO9646——“OSI协议一致性测试的方法和框架”,用自然语言描述了基于OSI七层参考模型的协议测试过程、概念和方法。但是,随着计算机网络技术的不断发展,新的协议越来越复杂,协议一致性测试工作遇到了很多困难。在这个过程中,大量形式化方法被引进到协议测试研究领域。1995年,ISO推出了“一致性测试中的形式化方法”国际标准,对协议一致性测试过程各个阶段使用的形式化方法进行了说明。但由于协议一致性测试本身的复杂性,使得该标准一直停留在草案阶段。对于互操作测试的研究技术基本上是从一致性测试继承过来的。由于对网络应用的需求急剧增长,网络性能已经变得与功能同等重要了。协议实现性能测试的研究工作也正在进行之中。在进行大量的测试实践的同时,理论研究也正在起步。

目前,国际协议测试研究领域已经取得了以下两点共识:(1)理顺了协议一致性测试的过程。(2)将形式化技术引入了协议测试领域,力图用严格的数学语言清晰、无二义性地研究协议测试的概念和方法。

但是,也发现这种方法存在着很多不足,其中最明显的就是这些理论研究与实际应用之间还存在着巨大的差距。

1.4 软件测试原则与特点

在明确软件测试的基本概念和方法后,接下来就是如何开展软件开发工作。本节讨论软件测试的一般性原则,以及软件测试工作的特点。1.4.1 软件测试的原则

软件测试,从不同的角度出发会派生出两种不同的测试原则。从用户的角度出发,就是希望通过软件测试能充分暴露软件中存在的问题和缺陷;从开发者的角度出发,就是希望测试能表明软件产品不存在错误,已经正确地实现了用户的需求。

无论是站在用户角度,还是站在开发者角度,软件测试都应该从公正、中立和客观的角度开展软件测试工作,这也是软件测试的基本原则。为此应注意以下几点。(1)应当把“尽早和不断地测试”作为开发者的座右铭。(2)程序员应该避免检查自己的程序,测试工作应该由独立的专业的软件测试机构来完成。(3)设计测试用例时,应该考虑到合法的输入和不合法的输入,以及各种边界条件,特殊情况下要制造极端状态和意外状态,比如网络异常中断、电源断电等情况。(4)一定要注意测试中的错误集中发生现象,这和程序员的编程水平和习惯有很大的关系。(5)对测试错误结果一定要有一个确认的过程。一般有A测试出来的错误,一定要有一个B来确认,严重的错误可以召开评审会进行讨论和分析。(6)制订严格的测试计划,并把测试时间安排得尽量宽松,不要希望在极短的时间内完成一个高水平的测试。(7)重复测试的关联性一定要引起充分的注意,修改一个错误而引起更多错误出现的现象并不少见。(8)妥善保存一切测试过程文档,意义是不言而喻的,测试的重现性往往要靠测试文档。在把握上述原则的同时,还应该根据软件测试工作的特点开展测试工作。下面讨论软件测试的特点。1.4.2 软件测试特点

1.完全测试程序是不可能的

初涉软件测试的人可能认为拿到软件后就可以进行完全测试,找出所有软件的缺陷,并使得软检达到完美。遗憾的是,这是不可能的,即使最简单的程序也不行,主要有如下4个原因。(1)输入量太大。(2)输出结果太多。(3)软件实现途径太多。(4)软件说明书没有客观标准。

以上这些因素使得测试条件难以确定。

例如,图1-5是一个含有4个分支和一个至少执行20次的循环的程序结构图。如果要对这个程序进行穷举测试,就要把从A到B的各种123路径全都测试一遍。不难看出,从A到B的不同路径共有5+5+5+…2040+5≈10。这是一个相当大的计算量。

2.软件测试是有风险的行为

软件如果不测试就会有风险,是一个公认的事实。例如,千年虫问题,如果不及时发现和排除,就会给计算机关键领域带来灾难。然而,如果说对软件进行测试同样也会带来风险,就不是所有人都能理解的。为什么会同样有风险呢?图1-5 一个程序结构图

软件是个复杂系统,其复杂性体现在软件实现的内容复杂性、开发过程复杂性和组织工作复杂性上。而软件测试的目的是为了发现故障,并加以排除。对一个复杂的软件系统,故障的排除往往可能又会带来新的软件缺陷。所以,软件测试又会带来一定的风险。

3.测试无法显示潜在的软件缺陷

有时,软件中存在的缺陷是无法全部清查出来的,即使知道肯定会存在软件缺陷。例如,Y2K问题,我们知道软件中存在设计缺陷,这些缺陷并不一定总是发生,但你还是要进行测试。对软件测试工作没有任何捷径,只有认真地测试下去。

4.发现的缺陷越多,说明软件缺陷越多

在软件测试中发现的缺陷越多,就说明软件中存在的缺陷越多,这是一个显然的事情,一个好的软件测试是能够发现足够多的软件缺陷和故障的。所以,发现的缺陷越多,说明软件中的缺陷越多,同时也说明软件测试工作或方法越好。

发现的缺陷越多,软件缺陷越多,但反之不一定成立。也就是说,软件缺陷多,并不一定能够都检查出来。如果一个软件的缺陷很多,而我们没有发现足够多的缺陷,则只能说明我们选择的测试方法和手段不好。

思考题

1.简述软件缺陷的含义。

2.说明软件缺陷、软件错误和软件失败的关系。

3.试评价一个软件测试的优劣的最主要指标。

4.“千年虫是不能被彻底清除的”这种说法是否正确?试说明原因。

5.黑盒测试是一种穷举测试,试说明穷举测试的含义。

6.简述ALAC测试的含义。

7.试比较渐进生命周期的测试工作和顺序生命周期的测试工作的共同点。

8.试从软件测试的范围角度,给出软件测试的分类。

9.简述单元测试的依据。

10.简述确认测试的测试目标。

11.给出α测试的执行者,并说明原因。

12.简述面向对象的软件测试的对象及采用的基本测试方法。

13.简述协议测试的内容以及采用的基本测试方法。

14.软件测试是有风险的工作,试解释这种说法的含义。

第2章 软件测试基础

本章讨论软件测试的基本方法,重点讨论软件测试黑盒法和白盒法;并对软件测试的过程进行讨论,重点讨论软件测试的设计和测试文档的使用。通过本章的学习,掌握软件测试的基本方法,并对软件测试作为一个工程组织所必要工程化方法有全面的了解。

按测试的范围和级别,软件测试可分为单元测试、综合测试、高级测试。无论是哪一级测试,所采用的方法基本有两种:白盒法(结构测试)和黑盒法(功能测试)。前者是针对系统内部实现的测试,而后者侧重于系统的外部功能和特性。

2.1 软件测试白盒法

白盒法是以程序的内部逻辑为依据。合理的白盒测试,就是要选取足够的测试用例,对源代码进行比较充分的覆盖,以便尽可能多地发现程序中的错误。2.1.1 逻辑覆盖法

逻辑覆盖是一组覆盖方法的总称。按照由低到高对程序逻辑的覆盖程度,又可区分为以下几种覆盖。

● 语句覆盖:使被测试程序的每条语句至少执行一次。

● 判断覆盖:使被测试程的每一分支至少执行一次,故又称分支覆盖。

● 条件覆盖:要求判断中的每一个条件按“真”、“假”两种结果至少执行一次。

● 条件组合覆盖:这是覆盖程度比前3种都强的一种覆盖,它与条件覆盖的区别是它不是简单地要求每个条件都出现“真”与“假”两种结果,而是要求让这些条件的所有可能组合都至少出现一次。

● 判断/条件覆盖:它使判断中的每个条件取得各种可能值,并使每个判断也取得“真”与“假”的结果。

下面通过一个实例说明上述各种覆盖方法的含义及测试用例的设计。

已知一个被测模块的程序结构如图2-1所示,设符号“∧”表示“and”运算,“∨”表示“or”运算,上画线“”表示“非”运算。

由图2-1可知,该程序共有4条不同的路径,L(a→c→e)、1L(a→b→d)、L(a→b→e)、L(a→c→d),也可以简写成234ace、abd、abe、和acd。其推导过程如下:

在以上的逻辑式中,由符号“and”连接起来的断言就是为了指明在遍历该路径时各个输入变量应取值的范围;符号“or”则划分了几组可选的取值。依据上述导出结果即可设计满足要求的测试用例。

1.语句覆盖

语句覆盖的含义是指在测试的过程中,软件测试者应选择足够多的测试用例,使被测试程序中每个语句至少执行一次。

例如,在如图2-1所示的流程图中,正好所有的可执行语句都在路径L上,故选择路径L设计测试用例,就可以覆盖所有的可执行语11句。图2-1 一个被测模块的程序结构

满足本例的测试用例是:[(2,0,4),(2,0,3)]覆盖ace[L]。1

本测试用例实际上只测试了条件为真的情况,如果条件为假,则使用本测试用例显然不能发现问题。此外,当第一个判断中的逻辑符“∧”写成“∨”,或者第二个判断中的逻辑符号“∨”写成“∧”时,本测试用例也不能查出上述错误。所以,语句覆盖是最弱的逻辑覆盖准则。

2.判断覆盖

判断覆盖的含义是指在测试的过程中,软件测试者应设计若干测试用例,并运行所测程序,使被测试程序中每个判断的真分支和假分支至少经历一次。

例如,在如图2-1所示的流程图中,如果选择路径L和L,则可12满足判断覆盖,其测试用例如下:

[(2,0,4),(2,0,3)]覆盖ace[L]1

[(1,1,1),(1,1,1)]覆盖abd[L]。2

如果选择路径L和L,则可得另一组测试用例:34

[(2,1,1),(2,1,2)]覆盖abe[L]3

[(3,0,3),(3,1,1)]覆盖acd[L]。4

由此看来,测试用例的取法并不是唯一的。此外,若把如图2-1所示的流程中的第二个判断中的条件X>1错写成X<1,那么利用上面两组测试用例,仍能得到同样的结果。这表明:只是判断覆盖不能确保一定能查出在判断的条件中存在的错误。

以上只讨论了两个出口的判断,还应将判定覆盖推广到多出口判断,如用case语句可进行多出口判断。

3.条件覆盖

用条件覆盖所设计的测试用例可使得程序中的每一个判断的每一个条件的可能取值至少执行一次。

例如,在如图2-1所示的流程中,事先可对所有条件的取值加以标注,比如:

● 对第一个判断,若条件A>1成立,则取真值为T,反之,取1假值为~T;若条件B=0成立,则取真值为T,反之,取假值为~T。122

● 对第二个判断,若条件A=2成立,则取真值为T,反之,取假3值为~T;若条件X>1成立,则取真值为T,反之,取假值为~34T,可选测试用例如表2-1所示。4表2-1 条件覆盖测试用例

比较这两组测试用例可以发现,第一组测试用例不仅覆盖了所有判断的取真分支和取假分支,而且覆盖了判断中条件的可能取值;第二组测试用例虽然满足了条件覆盖,但由于只覆盖了第一个判断的取假分支和第二个判断的取真分支,不满足判断覆盖的要求。为此,必须引入更强的覆盖,即判断—条件覆盖。

4.判断—条件覆盖

用判断—条件覆盖所设计的测试用例能够使得判断中每一个条件的所有可能取值至少执行一次,同时每个判断的所有可能判断结果至少执行一次。

例如,对于如图2-1所示的流程中的各个判断,若TTTT及~1234T~T~T~T的含义如前所述,则只需设计以下两个测试用例便可1234覆盖图2-1的8个条件取值、4个判断分支。

判断—条件覆盖表如表2-2所示。表2-2 判断—条件覆盖表

判断—条件覆盖也有缺陷。从表面上看,它测试了所有条件的取值,但事实并非如此。这是由于某些条件覆盖了另一些条件所致。比如,对于条件表达式(A>1)and(B=0)来说,若(A>1)的测试结果为真,则还要测试(B=0),才能决定表达式的值;而若(A>1)的测试结果为假,可以立刻确定表达式的结果为假。这时,往往就不再测试(B=0)的取值了,因此,条件(B=0)就没有检查。同样,对于条件表达式(A=2)or(X>1)来说,若(A=2)的测试结果为真,就可以立刻确定表达式的结果为真。这时,条件(X>1)就没有检查。因此,采用判断—条件覆盖,也不一定能查出逻辑表达式中的错误。

为彻底地检查所有条件的取值,可以将图2-1给出的多重条件判定分解,形成图2-2表示的由多个基本判断组成的流程图,这样就可以有效地检查所有的条件了。

5.条件组合覆盖

用条件组合覆盖所设计的测试用例能够使得每个判断的所有可能的条件取值组合至少执行一次。

现在仍来考察图2-1所给出的例子,先对各个判断的条件取值组合加以标记。例如,记:图2-2 分解为基本判断的例子(1)A>1,B=0 为T T,是第一个判断取真值的分支;12(2)A>1,B<>0 为T~T,是第一个判断取假值的分支;12(3)A<=1,B=0 为~T T,是第一个判断取假值的分支;12(4)A<=1,B<>0 为~T~T,是第一个判断取假值的分支;12(5)A=2,X>1 为T T,是第二个判断取真值的分支;34(6)A=2,X<=1 为T~T,是第二个判断取真值的分支;34(7)A<>2,X>1 为~T T,是第二个判断取真值的分支;34(8)A<>2,X<=1 为~T~T,是第二个判断取假值的分支。34

对于每个判断,要求所有可能的条件取值的组合都必须取到,在如图2-1所示的流程中的每个判断各有两个条件,各有4个条件取值的组合。取如表2-3所示的4个测试用例,就可以覆盖上述8种条件取值的组合。这组测试用例覆盖了所有条件的可能取值的组合,覆盖了所有判断的可取分支,但路径漏掉了L。测试还不完全。4表2-3 条件覆盖测试用例

说明:这里并未要求第一个判断的4个组和与第二个判断的4个4组和再进行组合。要是那样的话,就需要2=16个测试用例。

6.路径测试

路径测试就是设计足够的测试用例,覆盖程序中所有可能的路径。若还是以图2-1为例,则可以选择如表2-4所示的一组测试用例来覆盖该程序段的全部路径。表2-4 路径测试的测试用例2.1.2 基本路径测试法

基本路径测试是由TOM McCabe[MCC76]首先提出的一种白盒测试技术,基本路径测试法允许测试用例设计者导出一个过程设计的逻辑复杂性测度,并使用该测度作为指南来定义执行路径的基本集。从该基本集导出的测试用例保证对程序中的每一条语句至少执行一次。

1.流图符号

在介绍基本路径测试法之前,必须先介绍一种简单的控制流表示方法,即流图或程序图。流图使用图2-3中的符号描述逻辑控制流,每一种结构化构成元素有一个相应的流图符号。图2-3 流图符号

为了说明流图的用法,我们采用图2-4(a)中的过程设计表示法。其中,流程图用来描述程序控制结构。图2-4(b)将流程图映射到一个相应的流图(假设流程图的菱形决策框中不包含复合条件)。在图2-4(b)中,每一个圆称为流图的节点,代表一个或多个语句。一个处理方框序列和一个菱形决策框可被映射为一个节点。流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个节点,即使该节点并不代表任何语句。由边和节点限定的范围称为区域。计算区域时应包括图外部的范围。

任何过程设计表示法都可以被翻译成流图,图2-5显示了一个程序设计语言(Program Design Language,PDL)片断及其对应的流图。注意,对PDL语句进行了编号,并将相应的编号用于流图中。

程序设计中遇到复合条件时,生成的流图变得更为复杂。当条件语句中用到一个或多个布尔运算符(逻辑OR,AND,NAND,NOR)时,就出现了复合条件。在图2-6中,例如将一个包含复合条件的PDL片段翻译为流图。注意,为语句IF a or b中的每一个a和b创建了一个独立的节点,包含条件的节点被称为判定节点,从每一个判定节点发出两条或多条边。图2-4 程序流程图

2.环形复杂性

环形复杂性是一种为程序逻辑复杂性提供定量测度的软件度量,将该度量用于基本路径法,计算所得的值定义了程序基本集的独立路径数量,并为我们提供了确保所有路径至少执行一次的测试数量的上界。

独立路径是指程序中至少引进一个新的处理语句集合或一个新条件的任一路径。采用流图的术语,即独立路径必须至少包含一条在定义路径之前不曾用到的边。例如,图2-4(b)中流图的一个独立路径集合如下。

路径1:1-11

路径2:1-2-3-4-5-10-1-11

路径3:1-2-3-6-8-9-10-1-11

路径4:1-2-3-6-7-9-10-1-11

注意,每一条新的路径都包含了一条新边。路径1-2-3-4-5-10-1-2-3-6-8-9-10-1-11不是独立路径,意味它只是已有路径的简单合并,并未包含任何新边。图2-5 将PDL翻译成流图图2-6 复合逻辑

上面定义的路径1,2,3和4包含了如图2-4(b)所示的流图的一个基本集。简而言之,如果能将测试设计为强迫运行这些路径(基本集),那么程序中的每一条语句将至少被执行一次。每一个条件执行时都将分别取true和false。应该注意到基本集并不唯一。实际上,给定的过程设计可派生出任意数量的不同基本集。

如何才能知道需要寻找多少路径呢?对环形复杂性的计算提供了这个问题的答案。环形复杂性以图论为基础,为我们提供了非常有用的软件度量。可用以下三种方法之一来计算复杂性。

● 流图中区域的数量对应于环形的复杂性。

● 给定流图G的环形复杂性V(G),定义为V(G)=E-N+2,E是流图中边的数量,N是流图节点数量。

● 给定流图G的环形复杂性V(G),也可定义为V(G)=P+1,P是流图G中判定节点的数量。再回到图2-4。可采用上述任意一种算法来计算环形复杂性。

● 流图有4个区域。

● V(G)=11条边-9个节点+2=4。

● V(G)=3个判定节点+1=4。

因此,图2-4(b)的环形复杂性是4。

环形复杂性V(G)的值提供了组成基本集的独立路径的上界,由此得出覆盖所有程序语句所需的最少测试用例数量的上界。

3.导出测试用例

基本路径测试方法可用于过程设计或源代码生产。下面给出基本路径测试法的步骤,图2-7中的PDL所描述的过程“求平均值”将被用于阐明测试用例设计方法中的各个步骤。注意,“求平均值”虽然是一个简单的算法,但是仍然包含了复合条件和循环。图2-7 测试用例设计的PDL的节点已经标识

步骤1:以设计或代码为基础,画出相应的流图。创建一个流图,参考图2-7中“求平均值”的PDL。创建流图时,要对将被映射为流图节点的PDL语句进行标号,图2-8显示了对应的流图。

步骤2:确定结果流图的环形复杂性。可采用上一节的任意一种算法来计算环形复杂性V(G)。应该注意到,计算V(G)并不一定要画出流图,计算PDL中的所有条件语句数量(过程求平均值中复合条件语句计数为2),然后加1即可得到环形复杂性。在图2-8中,

V(G)=6个区域

V(G)=18条边-14个节点+2=6。

V(G)=5个判定节点+1=6。

步骤3:确定线性独立的路径的一个基本集。V(G)的值提供了程序控制结构中线性独立的路径的数量,在过程求平均值中,我们指定以下6条路径。

路径1:1-2-10-11-13

路径2:1-2-10-12-13

路径3:1-2-3-10-11-13

路径4:1-2-3-4-5-8-9-2-…

路径5:1-2-3-4-5-6-8-9-2-….

路径6:1-2-3-4-5-6-7-8-9-2-…

路径4、5和6后面的省略号(…)表示可以加上控制结构其余部分的任意路径。通常在导出测试用例时,识别判定节点是十分必要的。本例中,节点2、3、5、6和10是判定节点。

步骤4:准备测试用例,强制执行基本集中每条路径。测试人员可选择数据,以便在测试每条路径时适当设置判定节点的条件。满足上述基本集的测试用例如下。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载