魔兽7.0打击升级任务:软件测试概论1

来源:百度文库 编辑:九乡新闻网 时间:2024/04/27 15:44:03
第一章           绪 论
1.1    软件生存期
同其它任何事物一样,计算机软件从它的发生、发展到达成熟阶段,以至老化和衰亡,是一个历史发展的过程,这个过程称为软件的生存期(Life Cycle),包括下列六个步骤:
(1)计划(Planning):确定软件开发的总目标;给出软件的功能、性能、可靠性以及接口等方面的设想;研究完成该软件任务的可行性,探讨问题解决的方案;对可供开发使用的资源(软件、硬件、人力)、成本、可取得的效益和开发的进度等做出估计;制定完成开发任务的实施计划。
(2)需求分析(Requirement Analysis):由软件人员和用户共同对待开发的软件进行详细的定义和确切的描述,其结果是给出软件需求说明书(SRS:Software Requirement Specification)。
(3)设计(Designing):软件的设计分为两部分。一是概要设计(Preliminary Design),是指根据软件的需求说明书,软件设计人员应把需求说明书中各项需求转化为相应的体系结构,在结构中的每一组成部分是功能明确的模块,每个模块都能体现相应的需求。二是详细设计(Detail Design),是指对概要设计中给出的各个模块所要完成的工作进行具体的描述,为后来的编程打下基础。软件设计的结果是给出设计说明书。
(4)编码(Coding):利用某种计算机语言,把设计说明书中规定的内容转化为计算机可以接受的程序的过程称为编码。编码应以设计相一致,且结构清晰、易读、易修改。
(5)测试(Testing):根据软件的需求说明书、设计说明书和源代码,检验软件开发工作的成果是否符合要求的过程称为软件测试。软件测试是发现软件错误、提高软件可靠性与保证软件质量的重要手段。
(6)运行与维护(Running and Maintaining):对已交付用户的软件投入正式使用后便进入运行阶段,这个阶段可能持续若干年。在运行过程中,可能有多种原因需要对它进行修改,包括运行中发现了软件错误需要修正;为适应变化了的软硬件环境,而需要做相应的变更;为进一步增强软件的功能,或提高其性能,而使它进一步的完善和扩充等。
上述六步表明了一个软件从其酝酿开始,直至使用相当长的时间后,被新的软件代替而退役的整个过程。按此顺序逐步转变的过程可用一个软件生存期的瀑布模型加以形象化描述。如图1.1所示。图中自上而下的箭头代表了问题的一个求解过程,而自下而上的箭头代表了在实际项目的研制中,为确保软件质量,每一步骤完成后都要进行复查,如发现了问题,就要及时解决,以免问题积压到最后造成更大的困难。运行与维护的箭头表示在运行中可能需要多次维护。另外图中还指明了六个步骤划分的三个阶段,软件定义阶段、软件开发阶段和软件维护阶段。
值得注意的是,上述软件维护工作不可简单地看待仅仅是修改程序。在运行过程中若有必要修改,得提出充分的修改理由,经过审核,才能确定下来。接着需要经历制定修改计划、确定新的需求、修改软件设计、修改编码、进行测试以及重新投入运行等一系列步骤,这正是上述开发一个新软件的步骤。若是运行中多次提出修改,则将经历多次这些步骤。可用图1.2来表示这一过程,并称为软件的生存周期,也简称为软件的生存期。
1.2
软件危机
计算机系统工程分为硬件和软件两大范畴。计算机硬件的工程技术在过去的50多年中已经达到了相当成熟的状态。硬件设计技术和制造技术发展非常迅速,其自动化已经达到相当高的水平,硬件的可靠性已是一种现实的要求,而不在是一种愿望。
而在软件工程技术方面的情况则不同,软件是最难设计、最少可能成功、最容易出错、也最难管理的系统部分。据报道,在上世纪的最后十年里,计算机软件已成为系统瘫痪的主要原因。随着以计算机为基础的系统在数量、复杂程度和应用方面的激增,对软件的需要却在不断增加,因此促使供求矛盾日趋激化,这就是人们常说的软件危机。软件危机的来源主要表现以下几个方面:
(1)缺乏软件开发的经验:由于缺乏大型软件开发的经验和软件开发数据的积累,使得开发工作的计划很难制定。主观盲目地制定计划,执行起来和实际情况有很大差距,使得经费常常突破预算、工期一拖再拖,软件的投资者和用户对开发工作从不满意发展到不信任。
(2)需求不明确:作为软件设计依据的软件需求,在开发的初期提得不够明确,或者未能做出确切的表达。开发工作开始后,软件人员又未能和用户及时的交换意见,使得一些问题得不到及时解决而隐藏起来,造成开发后期矛盾的集中暴露。导致对多个错综复杂的问题既难于分析,又难于解决。
(3)缺少开发规范:开发过程中没有统一遵循的、公认的方法论或开发规范,参加工作的人员之间的配合不够严密,约定不够明确。加之不重视文字资料,使得开发文档很不完整。发现了问题,未能从根本上去找原因,只是修修补补。显然,这样开发出来的软件无法维护。
(4)软件的复杂性:软件的规模一般都比较庞大,大型软件有时会超过1亿行源代码。加之人们传统上的误区,往往是硬件难以实现的部分改用软件来完成,这使得软件既庞大,复杂性又高,甚至有时人的大脑已无法理解、无法驾驭人类本身所创造出来的复杂逻辑系统,投入使用后往往错误百出。
(5)缺乏有效的测试手段:软件的复杂性和软件测试的复杂性,使得难以研制有效的软件测试工具,导致测试效率不高、自动化程度低,测试花费时间多、测试成本高,这使得软件开发者只要求测试人员对软件做简单的测试,这无法保证软件的质量。
软件危机的事例是很多的。最著名的是上世纪六十年代,美国IBM公司开发的IBM360操作系统,这一项目在开发期共花费了5000万美元,总共投入的工作量是5000人年,共写出了100万行源程序。由于它太庞大,OS360变得相当不可靠,平均每次修改后的新版本都大约存在1000个左右的错误,而且有理由认为这是一个常数。另外,美国空军的范登堡中心在上世纪六十年代后期发生过多次导弹试射失败的事故,事后检查几乎都是由于软件有错误而造成的。
与软件危机有关的许多问题都起源于软件本身的特点、软件开发人员的弱点、以及人们对软件开发实质的种种不切实际的误解,计算机软件已经成为以计算机为基础的系统发展的重要瓶径。科学上的危机和其它领域的危机一样,解决危机的过程往往孕育着一种科学理论的诞生。自上世纪七十年代以来,科学家们一直在试图解决软件危机问题,虽然目前尚不能说软件的危机已经过去,但二十年来,软件技术的迅速发展,包括面向对象的技术、基于知识的软件开发环境、先进的软件测试工具等,为保证大型软件的研制提供了重要的基础。正是这些先进的技术,目前上亿行源代码的软件比比皆是。
1.3    软件质量
质量这一概念有许多不同的定义。在《词海》中,就把质量一词解析为“产品或工作的优劣程度”。国际标准化组织(ISO)把质量定义为“与一个产品或服务是否能够满足其指定的或蕴涵的需求有关的性质与特征的总合”。同其它产品一样,软件的质量也不是绝对的,在不同的情况下,对不同的人来说,软件质量的含义是不同的。
1. 软件质量要素
软件产品的质量是由许多软件性质构成的,这些性质常称为软件质量要素。一般来讲,软件的质量因素有下列11个。
(1)易使用性:是指软件易于使用的程度。
(2)完整性:保护软件不被未经同意的存储和使用的能力。
(3)效率:指软件对计算机资源的使用效率,包括运算时间效率和存储空间效率。
(4)可靠性:不失败的能力。
(5)正确性:程序完成其规约的程度。
(6)易维护性:在程序的操作环境中,确定软件故障的位置并纠正故障的难易程度。
(7)灵活性:当软件操作环境变化时,对软件作相应修改的难易程度。
(8)易测试性:对软件测试以保证其无错误和满足其规约的难易程度。
(9)易移植性:将一个程序从一个运行环境移植到另一个运行环境的难易程度。
(10)易复用性:复用一个软件或其部分的难易程度。
(11)互用性:将一个软件系统和其它软件系统组合在一起的难易程度。
2.软件质量要素的衡量标准
软件每个质量要素又包含一系列的衡量标准,具体为:
(1)易使用性:包括易操作性、培训、易交流性、输入和输出量、输入输出速度。
(2)完整性:包括存储控制、存储审查。
(3)效率:包括运行效率、存储效率。
(4)可靠性:容错性、一致性、准确性、简洁性。
(5)正确性:包括易追溯性、一致性、完备性。
(6)易维护性:一致性、简洁性、简明性、模块性、自我描述性。
(7)灵活性:模块性、一般性、易扩展性、自我描述性。
(8)易测试性:简洁性、模块性、检视、自我描述性。
(9)易移植性:模块性、自我描述性、硬件独立性、软件独立性。
(10)易复用性:通用性、模块性、自我描述性、硬件独立性、软件独立性。
(11)互用性:模块性、通讯共同性、数据共同性。
每个衡量标准的定义为:
(1)易追溯性:指在特定的软件开发与操作环境中,能够从软件的需求寻找出其相应的实现的能力与性质。
(2)完备性:指软件实现了其全部所需功能的性质。
(3)一致性:指在软件的设计与实现中采用统一的技术与术语的性质。
(4)准确性:指软件的输出与计算中的精度满足其需求的性质。
(5)容错性:指在非正常条件下,仍然能够操作软件的性质。
(6)简洁性:指软件以最容易理解的方式实现其功能的性质。
(7)模块性:指用一系列在很大程度上相互独立的模块来构成软件的性质。
(8)一般性:指软件所提供的功能具有应用范围广的性质。
(9)易扩展性:指易于对软件存储空间和计算功能进行扩充的性质。
(10)检视:指软件所提供的用于测量使用情况和识别错误的属性。
(11)自我描述性:指软件中包含它对功能的实现的解析性信息的属性。
(12)运行效率:指软件使用最少的处理时间的性质。
(13)存储效率:指软件在操作中对存储空间的需求最少的性质。
(14)存储控制:指反映对软件及其数据的存储进行控制的能力的性质。
(15)存储审查:指对软件及其数据的存储进行审查、记录能力的性质。
(16)易操作性:指决定软件的操作与操作过程的复杂程度与难易程度的性质。
(17)培训:指支持从初步熟悉到熟练操作软件的过度的性质。
(18)易交流性:指软件的输入与输出能够被人们理解的程度的性质。
(19)软件独立性:指决定对软件环境中的其它软件的依赖程度的性质。
(20)硬件独立性:指决定软件对硬件环境的依赖程度的性质。
(21)通讯共同性:指软件使用标准的通讯协议与界面的性质。
(22)数据共同性:指软件使用标准的数据表示格式的性质。
(23)简明性:软件的实现使用最少代码的性质。
每一个软件质量衡量标准又可以有多个不同的度量。软件质量度量有的作用于软件的代码,有的作用于软件开发过程中产生的中间结果和文档。
1.4  软件可靠性
1.硬件可靠性
所谓系统的可靠性,是指“一个系统在一定的环境下,在所给定的时间内能按预定的要求完成一定功能的概率”。
设一个具有N个元件的系统,经运行t时间后,有F(t)个元件失效,其余S(t)个元件仍然保持完好,则分别定义元件的可靠度R(t)和不可靠度Q(t)为:
定义元件的失效率Z(t)为单位时间内失效的元件数与非失效的元件数之比。
根据理论研究和大量统计得出,在正常的工作条件下,元件的失效变化趋势如图1.3所示。这就是硬件系统可靠性分析中著名的盆式曲线(Bathtub curve)。它表明系统在使用的开始阶段,其失效率是比较高的,但随着故障的排除,其失效率将稳定在一个基本上保持不变的常数,这个时期称为正常的使用期。由于受到周围环境、元件老化等因数的影响,在使用一定的时间后,系统的故障率开始上升,而且越来越高,直至系统被淘汰。
在正常的使用期,系统的失效率可以近似为一个常数l,则:
解这个方程,并考虑到R(0)=1,有:
硬件可靠性理论中的一个重要参数是系统的平均故障间隔时间MTBF(Mean Time Between Failures)和平均故障时间MTTF(Mean Time To Failures)。MTBF是指可修复故障的系统,而MTTF是指不可修复故障的系统。如果忽略这一点,MTBF和MTTF是混用的。因此,根据定义:
上述公式是硬件可靠性的基本理论,也是一套非常成熟的理论。
经过几十年的发展,硬件可靠性不但在理论上成熟的,而且在工程上也有许多提高可靠性的方法和工具。目前,一般出厂的硬件产品都有可靠性指标,如风险函数和MTBF等。
2.软件可靠性
软件的可靠性定义为:在给定的时间内,特定环境下软件正确运行的概率。正如前节所述,软件可靠性是软件质量的要素之一。对用户而言,同其它软件质量要素相比,软件可靠性是最重要的要素。
从其定义可以看出,软件可靠性涉及三个概念:给定的时间、特定的环境、正确运行的概率。
对给定的时间,是指由于软件的可靠性是随时间而变化的,根据软件可靠性的理论,软件每排除一个故障,其可靠性就提高一步。因此,在谈论软件可靠性的时候,一定要指明是什么时间的可靠性。
特定的环境是软件可靠性的一个重要的因素,它包括硬件环境、软件支撑环境和其它为保证软件正常运行所需要的环境。在评估软件可靠性时,一般要假设环境是正确无误的。
正确运行的概率情况比较复杂,软件运行包括选择输入数据和启动程序执行。但问题是如何选择输入数据才能真实的反应软件的可靠性?如何根据错误发生的时间来评估软件可靠性?软件可靠性的变化规律是什么?等等,类似的问题在软件可靠性理论的研究中都没有很好的解决。虽然如此,在过去的三十余年里,科学家在这个方面做了大量的研究,目前比较著名的有四十余种软件可靠性模型,由于工程数据的来源以及对软件可靠性认识上的不同,这些模型存在较大的差异。一个新的软件究竟用那种可靠性模型去评估更好,目前尚无定论。只能根据工程背景和个人的喜好去判断。
抛开寻求统一的软件可靠性模型,近几年来,许多科学家试图从工程的角度研究软件可靠性的部分内容,主要是软件的平均无故障时间MTBF、软件的故障率l等,这些参数对用户来说恐怕是更重要的。目前的许多军用软件、关系到国计民生的一些重要软件都有相应的可靠性参数评估,也是软件生产应达到的目标。
根据软件可靠性的理论,一个软件在交付之后,软件的可靠性就是确定的,只不过人们现在还没有很好的办法去认识它。抛开其它因素不谈,唯一能影响软件可靠性的是残留在软件中错误数目。随着软件在测试过程中或在使用过程中,软件错误的不断发现与排除,残留在软件中的错误会逐步减少,软件的故障率会逐步降低,因此,软件的故障率曲线应该类似于图1.4所示的曲线。这是软件可靠性建模的基本思想。
1.5  软件错误
1.     软件错误的概念
定义1.1:错误(Error):是指人们期望的和系统实际具有的状态或行为之间的偏差。
软件错误包括由系统分析或者程序设计而产生的全部错误。软件错误存在于软件生存期的各个阶段,凡是和预期的状态或行为不相符合的统称为软件错误。例如,制定的计划和实际不相符合的、需求说明书有问题的、设计说明书有问题的、程序编码有问题的、测试有问题的、运行结果不正确的、维护有问题的等等,都是软件错误。
定义1.2:失效(Failure):是指在软件运行期间出现的错误。它是因软件中存在的错误引起的、并在执行期间动态表现出来的和实际不同的状态和行为。
从这里可以看出,失败只是错误的一部分。
定义1.3:故障(Fault):是指软件中的物理缺陷。
故障也是错误的一部分,故障是指软件中实实在在存在的错误。故障可能引起软件的失效,也可能不引起软件的失效,人们总是通过修改软件中的故障来提高软件的可靠性。
定义1.4:缺陷(Defect,Bug):凡是没有按照要求所进行的工作统称为缺陷。
缺陷泛指系统中的一切错误。显然,缺陷是比错误范围更大的概念,缺陷除了包括错误所具有的全部属性外,像程序的多余物、难以理解的程序、难以修改的程序,文档不完全等,虽然这些可能并不能使软件失败,但是缺陷。通过修改软件中的缺陷来提高软件的质量。
从定义可以看出,上述四个概念是彼此相关的,有些文献中也经常是混用的。实际使用时应区分它们之间的层次和范围。
2.软件的缺陷数目与缺陷密度
软件的缺陷数目是指软件中所存在的所有缺陷的总和。而软件的缺陷密度是指每单位代码中的缺陷数目,这里,单位代码一般是KLOC或KSLOC(千行源代码),表示为缺陷数目/KLOC,或者缺陷数目/KSLOC。
软件工程师在工作中一般会引入大量的缺陷。统计表明,有经验的软件工程师的缺陷引入率一般是50~250个缺陷/KLOC,平均的缺陷引入率在100个缺陷/KLOC以上。即使软件工程师学过软件缺陷管理之后,平均的缺陷引入率也在50个缺陷/KLOC,也就是说,每20行代码中就有一个缺陷。再者从理论上看,人的认识能力是有限的,根据Hatton模型,对一般的软件,软件的缺陷数目可用下面的公式表示:
这里W是软件的复杂度,一般用源代码数目来表示。
从工程实践来看,目前世界上先进的软件开发组织所生产的软件,其缺陷密度可以达到2个缺陷/KLOC,一般的软件开发组织所生产的软件其缺陷密度可以达到4~40个缺陷/KLOC。据统计,在美国,安全第一的软件开发的代价是每行程序需花费500$。NASA所生产的软件其故障密度可以达到0.1个缺陷/KLOC,但其代价是每行源代码高达1000$。
软件的缺陷数目或者缺陷密度可以通过测试或者其它方法来计算。而残留在软件中缺陷数目或者缺陷密度只能通过评估来得到,例如根据测试的程度、或者根据软件可靠性模型等可以预测软件中残留的缺陷数目。
在安全第一或者一些重要的软件验收中,软件的缺陷数目或者缺陷密度是软件能否通过验收的重要标准。
3.软件错误的分类方法
软件的错误是非常复杂的,凡是人们能够想到的软件错误都是可能发生的。到目前为止,人们对软件错误的认识尚停留在表面上,其内在规律有待进一步研究。这也是目前软件测试技术发展比较缓慢的原因之一。虽然如此,人们还是可以根据软件错误的表现将其进行分类,常见的分类方法有:
(1)根据错误的征兆进行分类:这种分类方法是根据系统的输入和系统对输入的反应结果进行的分类。如表1.1所示。这种分类方法的好处是可以提高人们认识错误的严重程度,以便防范于未然。
表1.1 根据错误的征兆进行的分类
输入
系统反应
错误输入
正确输入
对输入的拒绝
正确
第I类型的错误(严重)
得出错误的结果
第II类型的错误(严重)
第III类型的错误(严重)
系统崩溃
第IV类型的错误(严重)
第V类型的错误(严重)
(2)根据错误的起因进行的分类:计算机系统中的每一个错误,究其原因,大都可以归结为下列三种情况之一,硬件或软件中的设计错误、由于环境或部件的老化引起的硬件恶化、错误的输入数据。显然,在软件生存期的不同阶段,每类错误的分布是不一样的,因此,这种分类方法的好处,一是了解错误在不同时期的分布规律。例如,在系统运行的早期所发生的错误,很有可能是设计错误或数据错误所引起的,在运行相当长的时间后所发生的错误可能是由于数据错误引起的,而在运行相当长的时间后,就有可能是硬件恶化引起的,这为判断软件错误的类型并尽快修复提供依据。二是根据这种分类,可以知道那些错误是可以排除的,而那些错误又必须通过是更换设备才能解决的。
(3)根据错误发生的持续时间来分类:一般可将其分为永久性错误和瞬时错误。永久性错误是指经常发生的错误,这类错误是不可怕的,因为它容易被排除。而瞬时错误恰恰相反,由于是偶尔出现,难以掌握其规律,故很难将其排除。
(4)根据错误的严重程度进行分类:不同的错误所产生的后果是不一样的。较少的错误例如数据格式不对,并不会产生什么后果,而有些错误,例如飞机导航软件出错,可能导致机毁人忘的严重后果。一般来讲,根据错误的严重程度可以分为:较少错误、中等错误、较严重错误、严重错误、非常严重错误和最严重错误。这里的分类,是根据错误引起后果的程度来分的,而不是根据错误对应故障的复杂性来分类的,有时一个较少的故障,例如,程序语句漏掉一个标点符号等,都可能产生严重的后果。
(5)根据开发阶段进行分类:在软件生存期的每个阶段都可能存在错误,即计划错误、需求分析错误、设计错误、编码错误、测试错误、运行与维护错误。由于生存期的每一个阶段又是下一个阶段的先导,也就是说,前一个阶段正确的设计是保证下一个阶段设计正确的必要条件。因此,要求一旦发现某个阶段存在错误,就要尽快将其排除。否则,越往后,排除故障的代价就越大,从这种意义上讲,这种分类法是必要的。
4.软件错误的分类
虽然上述给出了软件错误的五类分类方法,但前四种的分类方法只能给人们一个感性的认识,对排除故障并没有很大的帮助。
(1)根据软件开发阶段的分类:根据软件开发阶段的分类方法针对性比较强,便于人们认识错误和纠正错误。表1.2给出了一种基于开发阶段的分类方法,表中给出的错误数据比例是根据含有6877000个语句的源程序的错误(共16029个错误)进行统计的结果。
表1.2:基于开发阶段的分类方法
错误类型
描述
错误个数
百分比
软件需求错误
包括软件需求制定得不合理或不正确;需求不完全;含有逻辑错误;需求分析的文档有误。
1317
8.2%
功能和性能错误
包括功能和性能规定得有错误,或是遗漏了某些功能;为用户提供的信息有错误,或信息不确切;对意外的异常情况处理有误等。
2624
16.1%
结构错误
包括程序控制流或控制顺序有误;处理过程有误等。
4082
25.2%
数据错误
包括数据定义或数据结构有误;数据存储或数据操作有误等。
3638
22.4%
实现和编码错误
包括编码错或按键错;违背编码风格或是编码标准错误;文档有误等。
1601
9.9%
集成错误
包括软件内部和外部接口有误;各相关部分在时间配合、数据吞吐量等方面不协调等。
1455
9.0%
系统结构错误
操作系统调用错或使用错、恢复错误、诊断错误、分割及覆盖错误、引用环境错误等。
282
1.7%
测试定义与测试执行错误
包括测试设计错误、测试执行错误、测试文档错误、测试用例不充分等。
447
2.8%
其它类型错误
763
4.7%
(2)基于引起错误复杂度的分类:如表1.3所示。
表1.3:基于引起错误复杂度的分类
错误类型
描述
文档
注释、消息。
语法
拼写、标点符号、打字、指令格式。
联编打包
变更管理、库、版本控制。
赋值
说明、重名、作用域、限制。
接口
过程调用与引用、输入/输出、用户格式。
检查
出错信息、不合适的检查。
数据
结构、内容。
函数
逻辑、指针、循环、递归、计算、函数缺陷。
系统
配置、记时、内存。
环境
设计、编译、测试、其它系统支持问题。
5.软件错误的危害
(1)软件错误可能造成的危害:近年来,随着计算机应用领域的迅速扩大,计算机软、硬件新技术的不断涌现,人们对软件的质量提出了新的更高的要求。目前,计算机已广泛地应用于航天、航空、工业控制、交通、银行、金融、医疗等领域。在这样的应用领域中,软件质量往往关系到人民生命财产和生态环境的安危。一旦软件发生故障,就可能造成人的生命和财产的巨大损失和生态环境的破坏。例如:
· 国际上,计算机已普遍用于核电站的控制与安全保护,一旦软件发生故障,将会造成人员伤亡和环境污染。
· 在伦敦希思罗国际机场,平均每三分钟就有一架飞机起落,如果调度飞机场着陆次序的软件发生故障,将会造成飞机相撞的灾难。
· 波音747等大型客机都使用计算机自动导航系统,如果它发生故障,将会造成机毁人忘的事故。
· 在西方国家,铁路信号系统已计算机化。英国已计划在不久的将来实现铁路信号和扳道的全部自动化。铁路交通的安全性将进一步依赖计算机系统的正常运行。
· 在巴黎地铁系统中,由于使用计算机进行有效的调度和安全控制,火车的行驶速度得以加快,火车之间的间隔得以缩短。
· 现代通信技术和网络技术的发展,使得人们相互之间的信息交换达到完全自动化,如果主控计算机出现故障,则它所控制的用户对外的信息交流将被中断,所造成的损失是难以估量的。
· 一旦银行系统的计算机出现故障,将会造成混乱。这也是目前银行系统尚需人工备份资料的重要原因。
以上类似的例子很多,难以枚举。随着计算机科学、信息科学和其它自然科学的发展,我们有理由相信,人们将会越来越依靠计算机,计算机将是人类生活的重要组成部分,到那时,计算机的错误将不在仅仅是一个技术问题,而将完全变成一个普遍的社会问题。
(2)软件错误已经造成的危害:软件的错误给人类生活已经造成的危害的事例是很多的,这里仅举几个例子。
· 欧洲航空航天局发射的啊里亚那火箭,由于软件的错误而使发射失败,所携带的卫星报废,损失巨大。
· 中国的´´卫星,也是由于软件的错误,在运行不到一年后就失去作用。根据事后的分析表明,仅仅是由于一个非常简单的软件错误而使耗资巨大的卫星报废,多么可失!
· 由于控制放射性治疗设备的软件错误,在加拿大已经造成了多起癌症病人因受到过量放射性辐射而死亡的事故。
· 在英国,由于放射性治疗设备中计算辐射量的软件错误,发生了癌症病人因放射性辐射太低而得不到适当治疗的事故。
· 在伦敦,救护车调度软件刚刚投入使用几小时就发生故障,造成急诊病人延误达十几小时。
· 飞机自动控制软件的错误造成了飞机在特技飞行表演时坠毁。
· 自动行李处理系统的小小软件错误使丹佛国际机场飞机受阻,到达的行李空等九个月。
类似的例子也很多。当我们每天依靠计算机进行工作时,一旦计算机发生错误,给我们造成的危害是苦不堪言,可能我们几个月甚至几年的劳动会付诸东流。表1.4给出了部分计算机系统实效源的统计数据。
表1.4计算机系统实效源的统计数据
系统
数据发表年份
硬件(%)
软件(%)
维护(%)
操作(%)
环境(%)
AT&T ESS
1978
20
15

65

Tandem
1985
18
26
25
17
14
Bellcore
1986
26
30

44

Tandem
1987
19
43
13
13
12
可见,软件故障正逐渐成为导致计算机系统失效的主要因素。
1.6  软件测试概论
1. 软件测试的概念
由于软件及软件错误的复杂性,长期以来,人们对软件测试的认识一直是模糊的。许多科学家从不同的角度给出了软件测试的不同定义,但总体来看,都是不全面的。Myers认为:“程序测试是为了发现错误而执行程序的过程”,该定义明确给出了软件测试就是为了发现软件中的错误,这一概念目前被人们所公认。但该定义认为软件测试仅仅是程序编码的测试,这显然是不全面的,在某种意义上说是有害的,因为许多软件错误并不是编码上的错误,而人们往往会忽略这一点。
1983年IEEE给出的定义是:“使用人工或自动手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求或是弄清楚预期结果与实际结果之间的差别”。应该说该定义是比较全面的。应该说,上述两个定义都是以检验软件是否存在错误为目的,也可以说是一种正确性测试。但也有人不同意这种观点,认为软件测试还应包括可靠性测试、健壮性测试、性能测试、效率测试等。作者认为,软件的测试是和软件的需求是密切相关的,对一般的民用软件,正确性测试是能够满足要求的。而对某些关键性软件,如导航控制软件、核电站控制软件等则必须进行后几种测试。但要指出的是,进行后几种测试,仅仅编写一个软件测试程序是不够的,往往研制必须的硬件环境,其代价往往是很大的。因此,本文我们所论述的测试一般都是指面向软件正确性的测试。
2. 如何认识软件错误
目前,影响软件测试技术发展的一个重要因素就是人们对软件测试在认识上存在的误区。误区之一是设计者、程序员对自己所做的工作特别有信心,不愿意让别人来挑自己的毛病。误区之二是既然软件测试不能证明软件是正确的,何必又需要测试呢?误区之三是由于软件测试是一种辅助性的工作,既费力又难以出成绩。很多人不愿意做这个工作。因此,解决人们认识上的问题是非常有必要的。
(1)软件能否彻底的测试:回答是不能。例如,一元二次方程ax2+bx+c=0求根的程序,该程序的3个输入a、b、c是实数,假设计算机有32位(假设8位阶码),每个数据的数据个数至少为1030,则总的数据个数要大于1090。要彻底测试一个软件,就要每个数据都至少运行一次,这是目前所有计算机都不可能做到的。上述还仅仅考虑了输入的一部分,在使用中,用户有意或无意的可能输入其它数据,例如字符等。考虑到这些因素,要彻底测试一个软件是不可能的。
软件不能被彻底的测试并不否定软件测试的作用。正如一个再好的医生也不可能检查出病人的所有毛病一样,据此就否定医生的作用是错误的。早在1972年,Dijkstra曾说过一句名言:“软件测试只能表明错误的存在,而不能表明错误不存在”。
(2)早期的错误是否应在早期排除:回答是肯定的。软件的错误存在于软件生存期的各个阶段,在每一阶段发现的错误都应在此阶段将其排除掉,否则,越往后,排除讲越困难。有人作过统计,在后一个阶段排除前一个阶段的错误,其费用将提高10倍。经过近些年来软件工程技术的实践,人们对这个问题已不在有什么怀疑。但存在的问题是:不是人们发现了早期的错误不排除,而是没人去发现早期的错误,这种情形很普遍,是软件设计的灾难,必须引起足够的重视。
(3)能否用验证技术代替软件测试:回答是不能。程序验证是采用形式化的方法来检验软件是否正确,从理论上看,该方法对检验软件的错误是完备的。但实际上,程序验证技术有很大的局限性,实践表明,该方法只能对一些小的例子是有效的,大中型软件正确性验证无论从方法上还是从验证效率上,都是不实际的。此外,经过程序验证的软件,需求分析错误、接口错误等也检验不出来。
3. 软件测试的费用
统计表明,软件测试与维护的费用要占到整个软件开发费用的50%以上。图1.5给出了估计修复软件缺陷费用的现行行业标准(资料来源:B.Bohem,Software Engineeering,IEEE Transactions on Computer,1976.12)。表明缺陷发现的越晚,费用将如何惊人的增长。
4.
软件测试的意义
(1)减少软件的缺陷数目或者降低软件的缺陷密度:通过测试可以发现软件中存在的缺陷,通过完全的修改这些缺陷,可以减少软件中缺陷的总数目或者降低其缺陷密度。
(2)提高软件的可靠性:软件的缺陷数目是影响软件可靠性的主要因素,通过测试减少软件的缺陷数目可以达到提高软件可靠性的目的。
(3)评估软件的性能指标:通过软件测试,根据所发现的缺陷数目和发现缺陷的时间,可以评估软件的可靠性等指标。即使软件测试没有发现缺陷,也同样可以达到这个目的。
(4)增加用户对软件的信心。软件通过了何种测试对用户来说是非常重要的,严格的软件测试可以大大用户对该软件的信心。
1.7 软件测试方法
软件的错误存在于软件生存期的各个阶段,不同阶段的错误性质是不同的,不同的错误对应了不同的测试方法。本章所论述的静态测试方法、动态测试方法、黑盒测试方法和白盒测试方法就是根据上述问题而发展起来的。有些方法是通用的,例如静态测试技术,在软件生存期各个阶段的错误检测中都可以使用,而有些方法只是对某个阶段才能使用,例如,动态测试技术,只有当程序出来以后才能进行动态测试。不同的测试方法对各个阶段错误检测的效率也是不同的,有些时候,在同一阶段,当各种方法组合使用时,错误检测的效果会更好。此外,对程序测试而言,分步测试更有利于尽快的发现错误,减少测试的开销。
1.静态测试方法
(1)测试方法:在软件开发过程中,每产生一个文档,都必须对它进行测试,以确定它的质量是否满足要求。静态测试的基本特征是在对软件进行分析、检查和测试时不实际运行被测试的程序。它可以对各种文档进行测试,是软件开发中十分有效的质量控制方法之一。在软件开发过程中的早期阶段,由于可运行的代码尚未产生,不可能进行动态测试,而这些阶段的中间产品的质量直接关系到软件开发的成败与开销的大小,因此,在这些阶段,静态测试的作用尤为重要。目前,比较常用的静态测试方法有:Yourdon的结构化走通法和Fagan检查法。
1) 结构化走通法。结构化走通是由一组人员对一个文档从多种不同的角度进行检查,以尽可能多地发现其中的错误。它以该文档的产生者为中心,由产生者向参加审阅的其他人员报告其文档。所发现的错误或怀疑是错误的问题则由召集人记录在案。审阅的中心问题是发现错误,而不是纠正错误。在结构化走通的审阅过后,由文档的产生者将记录在案的错误纠正。
Yourdon指出,结构化走通的审阅过程应该由如下人员组成:
· 报告者:该文档的拥有者和文档的产生者;
· 召集人:组织并主持审阅;
· 秘书:负责事先将文档散发给有关人员,记录审阅过程和结果,并将记录递交给报告者;
· 维护者:将负责维护该文档的人员的代表;
· 标准检查员:负责对照该文档所适用的标准进行检查的人员;
· 用户代表:负责从其使用者的观点检查该文档;
· 其他人员:任何对该文档的检查能够有所贡献的人员。
2)Fagan检查。Fagan检查是由IBM发展起来的,其总的原理和Yourdon的结构化走通非常类似。但是Fagan检查是将审阅放在一个质量计划、度量和控制的更广泛的环境下,使之具有双重目的:一是发现产品的错误;二是通过对错误的分析、统计,提供今后对所发现的同类错误进行控制的数据。Fagan检查强调的是对错误进行分类和统计,从而发现共同的错误类型和将来避免这类错误的方法。简言之,Fagan检查强调对开发过程的反馈和从错误中吸取教训。
(2)测试内容。静态测试测试的范围和内容很多。从范围上讲,凡是能形成文档的设计都应该进行测试。这包括需求定义文档的静态测试、概要设计文档的静态测试、详细设计文档的静态测试、编码文档的静态测试、测试文档的静态测试等。从内容上看,针对不同的文档,虽测试的内容不尽相同,但都是按照软件质量的要求,即第一章给出的软件质量的11个要素进行测试。下面以源代码的静态测试为例说明静态测试所包括的内容。
1)完备性测试。检查代码是否完全、准确地实现了设计规约中所规定的内容;代码是否满足设计要求;代码是否创建了所需的数据库或其它初始化数据;是否有未引用的或未定义的变量、常量或数据类型。
2)一致性测试。检查代码在逻辑上与设计规约是否一致;是否自始自终使用了相同的格式、调用约定、结构等。
3)正确性测试。代码是否符合标准;变量的定义和使用是否都正确;注释是否正确;子程序调用的参数个数是否正确等。
4)易修改性测试。检查代码是否避免了直接使用地址,而采用标号或符号常量;代码是否由单入口、单出口的子程序构成;是否有交叉引用数据等。
5)可测试性测试。检查程序中是否有递归;是否包含了无穷循环等。
6)健壮性测试。检查代码是否防止可以发现的运行时刻的错误,如:下标变量越界、除数为0、栈溢出等。
7)结构化测试。检查程序的每一个功能是否都可以作为一块代码而识别出;循环是否只有一个入口等。
8)易追溯性测试。检查是否有一个交叉引用表,通过它可以便捷地从代码找到相应的设计;是否有修改历史记录,它记录对代码的所有修改历史和修改原因。
9)易理解性测试。检查注释是否简洁、充分;是否有不必要的复杂代码等。
10)可验证性测试。检查实现是否避免了使用测试难度大的技术和方法等。
(3)方法评述:静态测试主要靠人来完成的。虽然近些年来,从需求分析开始的软件生存期的各个阶段,开发了不少的工具,但短期内难以实现其设计的自动化和测试的自动化。因此,静态测试错误发现的多少完全依赖于测试的组织和测试者的水平,实践也表明在这个方面有许多成功的范例,例如中国的某个有数万行航天类控制软件,通过静态测试发现了其中的3000多个缺陷。但从目前静态测试的效果来看尚存在如下的一些问题。
1)认识不足。特别是决策者的认识不足。但这种情况正在改变。
2)测试的问题太多,不知从何处下手。解决这个问题的办法是可以对静态测试的范围和内容进行分门别类的测试,效果可能会更好。
3)自动化或半自动化的测试工具是必须的。有了这个工具,可以大大提高测试者的兴趣和发现错误的能力。但目前基本上是空白。
4)开发的软件缺少静态测试所必须的文档。这个在一些地方还十分突出,但这种情况正在好转。
2. 动态测试方法
静态测试只能定性的分析软件的质量,而不能定量。从这种意义上讲,静态测试是有很大的局限性,但这并不否定静态测试的重要性,因为,就发现一个错误而言,动态测试的花费要大得多。
所谓动态测试,就是通过运行软件来检验软件的动态行为和运行结果的正确性。因此,动态测试只存在于软件生存期的编码阶段之后。动态测试包括两个基本要素:一是被测程序,二是用于运行软件的数据,称为测试数据,程序一次运行所需要的测试数据称为测试用例,所以测试数据是测试用例的集合。
动态测试的流程如图1.6所示。因此,一个成熟的动态测试软件必须回答下列问题:
1)  如何选择或产生测试用例?
2)  如何组织软件的测试运行?
3)  如何考察和记录软件动态运行的行为?
4)  如何判断软件动态行为的正确性?
5)  测试过程如何结束?
6)   如何通过软件测试的结果分析软件的某些性质,如软件的可靠性等?
动态测试近三十年来,由于有其比较强的错误检测能力,受到人们的普遍重视,产生了许多测试方法。这些方法可以从两个角度对其进行分类。
(1)按照产生测试数据以及判断测试充分性的方法:可以分为如下四类:
1)结构性测试。结构性测试旨在充分地覆盖软件的结构,并以软件中的某些元素是否都已得到测试为准则来判断软件测试的充分性。本书将在第四章做详细介绍。
2)排错性测试。排错性测试旨在排除软件中包含某类错误的可能性,并根据一个测试数据集排除软件错误可能性的能力来度量其测试的充分性。
3)分域测试。分域测试方法通过对软件的实现或/和软件需求进行分析,将软件的输入空间划分成一系列子空间,然后在每一个子空间内选择一个或多个测试用例。
4)功能测试。功能测试是根据软件所需的功能或/和所实现的功能选择测试数据,分析测试的充分性。
(2)按照产生测试数据所根据的信息来源:可以分为下列四类:
1)以程序为基础的测试。它通过对程序的分析来产生测试数据,它还以程序被执行的程度来判断测试是否充分。
2)以需求和功能的规约为基础的测试。它通过分析软件的需求和功能规约来产生测试数据,并根据软件需求和功能规约中所规定的功能和性能是否都得到了充分的检验来判断测试是否充分。
3)程序和需求相结合的测试。它综合考虑软件的需求和实现来产生测试数据,判断测试的充分性,这是目前最常用的方法,可以拟补(1)和(2)单个方法的不足。
4)以界面为基础的测试。以界面为基础的测试仅仅依靠软件与其运行环境之间的界面来产生测试数据,并以界面和界面内所包含的功能是否都得到测试来判断测试的充分性。这是面向对象技术常用的测试方法。
3.黑盒测试方法
黑盒测试又称功能测试、数据驱动测试和基于规格说明的测试。用这种方法进行程序测试时,被测程序被当作一个打不开的黑盒,测试者是在完全不知道程序内部结构的情况下进行的,而只需知道程序的输入和输出之间的关系亦可。因此,黑盒测试是基于用户的测试。测试者正是依靠这个关系来产生测试用例,并判断运行结果的正确性。进行黑盒测试必须要弄清楚下列几个问题:
(1)软件的功能到底有多少?这是进行黑盒测试所必须的,否则,测试是不可能充分的。
(2)测试的层次是什么?也就是说,测试要在哪个层次上进行。因为,在软件的总体功能之下可能有若干个层次的功能,在需求分析层描述的功能一般比较粗,在这个层次上进行测试可能会漏掉一些细节。而在代码层则一般比较细,但在这个层次上进行测试可能会忽视各个功能之间存在的相互作用和相互依赖的关系。因此测试人员需要考虑并兼顾各个层次的功能。也正是由于这个原因,使得黑盒测试的影响大大降低。
黑盒测试是必要的,有时也是必须的。所谓是必须的,是作为测试者而言,并不总能得到程序的源代码,而往往只有程序的说明书和执行代码,在此情况下,唯一的测试方法就必须采用黑盒测试技术。所谓必要的,是相对白盒测试而言的,主要表现如下几个方面:
(1)白盒测试并不是最后的测试手段,因为白盒测试验证不了诸如软件可靠性等参数,而这恰恰是黑盒测试所要做的工作。
(2)黑盒测试不能对程序的特定部位进行测试,因而无法对程序进行排错。而这恰恰是白盒测试可以做到的。
对一般的测试软件系统,采用黑盒测试和白盒测试相结合的测试方法,往往会取得更好的测试效果。
4.白盒测试方法
白盒测试又称结构测试、逻辑驱动测试或基于程序的测试。用这种方法进行程序测试时,测试者可以看到被测程序,并利用其分析程序的内部构造。因此,白盒测试是基于程序的测试。白盒测试是根据被测程序的内部结构设计测试用例的一类测试。它要求对被测程序的结构特性做到一定程度的覆盖,因此,白盒测试也称为基于覆盖的测试技术。到目前为止,已经提出了几十种覆盖技术,我们将在第四章做详细论述。但必须说明无论那种白盒测试的覆盖技术,即使达到100%的覆盖率,也不能保障把所有的错误都检测出来。对于某些在规格说明书中规定的,但在实现中被漏掉的功能,无论那一种测试也检测不出来的。因此,提高结构测试的覆盖率只能增强人们对被测软件的信心。
动态测试和静态测试是一种分类方法,黑盒测试与白盒测试又是另外的一种分类方法。二者是有许多交叉的。动态测试含有黑盒测试与白盒测试,静态测试一般只含有白盒测试。黑盒测试一般都是动态测试,而白盒测试一般都包含动态测试和静态测试。
5.其它测试方法
(1)可靠性测试与排错性测试:可靠性测试是以验证或评估软件的可靠性为目的,并不关心测试过程中所发现的错误。正如前边所述,软件错误是不可能完全避免的,软件存在的错误并不影响软件的交付,用户所关心的是软件的可靠性究竟是多少。排错性测试则恰恰相反,该测试是以排除软件错误为目的的,一旦测试发现错误,就立刻予以排除。一般而言,排错性测试用于软件测试的早期阶段,并以白盒测试为主要测试手段。而可靠性测试用于软件测试的末尾阶段,一般以黑盒测试为主要测试手段。
(3)人工测试与自动测试:顾名思义,人工测试是采用人工的手段对软件实施的测试,它是相对自动测试而言的。和静态测试不同,人工测试贯穿于软件生存期的各个阶段,并通过人工运行和审查会的形式对软件实施的测试。人工测试中,主要是测试人员根据一些成熟的软件设计规则对软件的正确性等进行审查,检验所进行的设计是否能满足需要。实践表明,人工测试是非常有效但往往被忽略。统计表明,人工测试能发现30%~70%的错误,IBM公司的代码审查会的查错率更高,竟能查出全部错误的80%。软件测试还有其它更多的测试方法,在后面的几章中将有详细的叙述。
1.8  软件测试步骤
图1.7给出了软件的生存期和软件测试之间的关系。也可以用图1.8来描述,即软件测试的V模型。软件测试是要分步进行的,为什么呢?打一个比方,对一个1000行的程序搜索一个错误和10个100行的程序搜索一个错误其代价是不一样的。从软件测试的角度来看,分步测试的原因有三个:一是和上述例子类似,即把大问题划成小问题,这更有利于问题的求解。二是软件则不同的层次上,其错误的类型是不一样的,其测试的侧重点和测试方法是不同的。其三是在级别高的层次上检测低级层次上的错误其花费要大幅度的增长,图有人做过统计,在下面的给出的四个测试层次上,即单元测试、集成测试、确认测试和系统测试,层次每增加一
级,测试一个错误的代价就要提高10倍以上,图1.5也充分的说明了这一点。可以用图1.9来表示各个测试步骤之间的关系。
(1)单元测试:单元测试是对软件中的基本组成单位进行测试,如一个模块、一个过程、一个函数或一个类,等等。单元测试是软件测试最基本的组成部分,也是最重要的部分之一。其目的是检验软件基本组成单位的正确性。一个软件单元的正确性是相对该单元的规约而言的,因此,单元测试是以被测单位的规约为基准。单元测试要注意如下的问题:
1)单元的大小要适宜。一般是以程序中给出的模块为准,但有时一个模块可能太大,有时也可能太少,这二者都会对单元测试的效果产生不利的影响。一般来讲,一个单元模块在几十行到几百行源代码为宜。
2)单元测试一般要给出驱动模块和桩模块。一般来讲,一个单元是不能独立运行的,因此,要设计一些模块,使之能驱动被测模块的执行,这种模块称之为驱动模块。另外,一个被测模块还可能调用其它的模块,而在测试一个单元时,一般是不考虑其它模块的测试的,因此设计一类模块称之为桩模块,用于模拟运行被测模块时调用的其它模块。
(2)集成测试:集成测试是在软件系统集成过程中所进行的测试,其主要目的是检查软件单位之间接口的正确性。它根据集成测试计划,一边将模块或其它软件单位组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各组成部分是否合拍。集成测试的策略主要有自顶向下和自底向上两种。
1)自顶向下的集成测试策略从软件的主控模块入手,将其直接调用的模块首先与其集成。并将该子系统所调用的过程和所使用的数据用一些简单的代码——即桩模块代替,在桩模块的帮助下,可以运行并测试这一子系统,直至测试结果满足要求为止。然后,将这一子系统所调用的模块与该子系统集成,并重复上述过程,直到测试完毕。
2)自底向上的集成测试策略则相反,从软件中不调用任何其它单元的模块入手,把直接调用该模块的程序与其集成在一起,在驱动模块的帮助下,完成该子系统的测试。然后,再把调用该子系统的模块和该子系统集成,并重复上述过程,直到测试完毕。
这两种方法各有优缺点,在实践中,可将两种方法相结合。
(3)系统测试:系统测试是对已经集成好的软件系统进行彻底的测试,以检验软件系统的正确性和性能(如运算的精度、系统的反应时间)等是否满足其规约所指定的要求。系统测试在许多情况下是比较复杂的,仅仅编制一个测试程序是不够的,往往伴随着要建立一个软硬结合的测试系统。
(4)验收测试:验收测试旨在向软件的购买者展示该软件系统满足其用户的要求。它的测试数据通常是系统测试数据的子集。所不同的是,验收测试常常需要用户的代表在场,甚至在软件安装的现场。这是投入使用前的最后测试。
(5)回归测试:回归测试是在软件维护阶段,对软件修改之后进行的测试。其目的是检验对软件进行的修改是否正确。这里,修改的正确性有两重含义:一是指所作的修改达到了预期的目的,如错误得到改正,能够适应新的运行环境。二是指不影响软件的其它功能的正确性。
回归测试通常包括重新运行系统测试中的部分测试数据。因此,需要搞清楚哪些测试数据是与被修改的代码有关。在软件开发过程中,保留测试数据与程序代码之间的关系对回归测试具有很大的帮助。回归测试还往往需要使用针对所修改的代码的测试数据。这样的测试数据可以根据单元测试、集成测试和系统测试的方法产生。
1.9 软件测试与软件可靠性
从理论上看,软件的可靠性只和存在于软件中的故障有关。假设软件S中有n个故障f1,f2,…,fn,直观上,软件S的可靠性R可以表示为RS= RS(f1,f2,…,fn)。假设D是S的定义域,f(D)是D中每个点取值的概率,{D,f(D)}是S的运行剖面,在{D,f(D)}下,假设每个故障被检测的概率为qi=P(fi),这里,所谓的检测概率是指一次性检测该故障的概率,或者说,一次运行产生错误的概率。若S中存在n个故障,则:
定理1:若n个故障f1,f2,…,fn是相互独立的,则:
实际上l即是在存在n个故障的前提下,软件S的风险函数。
根据软件可靠性理论,软件S初始的故障数目可以假设为一个常数n。随着测试的进行,存在于软件S的故障不断的被排除(假设是完全排除,即不引入新的故障),存在于软件中的故障会越来越少。由于每排除一个故障后,剩余的存在于S中故障集合是排除前存在于S中故障集合的子集,因此不难证明:
定理2:设F1和F2是软件S两个故障集合,若F1ÍF2,则l(F1)£ l(F2);若F1ÌF2,则l(F1)< l(F2)。
可以看出,随着测试的进行,故障被检测并被排除,软件的风险函数越来越少,其可靠性会越来越高。因此,软件测试是发现软件故障,提高软件可靠性的重要手段。
【例1.1】 假设软件中有5个错误,每个错误被检测的概率分别为:q1=10-6,q2=10-7,q3=10-8,q4=10-9,q5=10-10,时间单位是秒。假设错误的检测与排除是按照从检测概率大的到检测概率小的依次进行,因此,其对应的风险函数和平均无故障时间分别为:
(1)       初始状态:l1=1.11´10-6,MTBF=31.25(天)(每天按8小时计算)
(2)       排除第一个故障后:l2=1.11´10-7,MTBF=312.5(天)
(3)       排除第二个故障后:l3=1.11´10-8,MTBF=3128.1(天)
(4)       排除第三个故障后:l4=1.11´10-9,MTBF=31565.7(天)
(5)       排除第四个故障后:l5=10-10,MTBF=347222.2(天)
1.10  影响软件测试效率的因素
同其它任何一个产品相比,软件的测试是更为复杂的,这主要是因为到目前为止,人们对软件的错误发生的规律认识的还不是很清楚,软件测试也缺少有效的工具。影响软件测试的效率的因素是很多的,除了测试方法之外,主要因素还有人为因素、软件类型、错误类型、测试充分度等。下面对这些因素进行一些分析。
1.人为因素
在软件测试缺少自动化程度高的测试工具的前提下,软件测试的许多工作是由人来完成的。因此,人的因素是影响测试效率的重要方面。Basili和Selby的实验数据清楚地揭示出了人为因素的作用。表1.3揭示了不同水平层次的测试人员在发现软件错误的数量和测试效率的差异。这里,阶段1、2和3分别对应单元测试、集成测试和系统测试。
表1.3 人为因素对测试效率的影响
测试者水平层次
阶段
初级
中级
高级
平均值
标准差
平均值
标准差
平均值
标准差
发现错误的个数
1
3.88
1.89
4.07
1.69
2
3.04
2.07
3.83
1.64
3
3.90
1.83
4.18
1.99
5.00
1.53
发现错误的效率
1
1.36
0.97
2.22
1.66
2
1.00
0.85
0.96
0.74
3
2.14
2.48
2.53
2.48
2.36
1.61
2.软件类型
软件类型也是影响测试效率的一个重要因素,表1.4是Basili和Selby的实验数据。P1~P4代表了4个不同的程序。
表1.4 软件类型对测试效率的影响
程  序
阶段
P1
P2
P3
P4
平均值
标准差
平均值
标准差
平均值
标准差
平均值
标准差
发现错误的个数
1
4.07
1.62
3.48
1.45
4.28
2.25
2
3.23
2.20
3.31
1.97
3.31
1.84
3
4.19
1.73
5.22
1.75
3.41
1.66
发现错误的效率
1
1.60
1.39
1.19
0.83
2.09
1.42
2
0.98
0.67
0.71
0.71
1.05
1.04
3
2.15
1.10
3.70
3.26
1.14
0.79
3.错误类型
各种不同的测试方法检测不同错误类型的能力也是不同的。错误的分类方法目前有许多种,前边已经给出了比较详细的分类方法,为分析方便,下列分类是其中的一种简单的分类方法。
(1)初始化错误:初始化代码中的错误;
(2)控制错误:控制转移的条件或转移地址错误;
(3)数据错误:包括程序中的常数、数据库中的数据错误等;
(4)计算错误:计算代码错误
(5)集成错误:各模块之间、软件与环境之间的错误
(6)容貌错误:人机界面、打印格式等错误。
图1.10中是根据是Basili和Selby的实验数据整理的。
4.测试充分度
测试充分度是反映了在给定的测试方法下软件被测试的程度。设M是给定的测试方法,在M下,软件S应被测试的元素的集合是T,而实际上被测试元素的集合为U,则U/T即是测试充分度。Frankl和Weiss发现,只有当测试的充分度接近100%时,才能使测试发现错误的能力得到发挥。如图1.11所示。
1.11  软件测试工具
软件测试工具是提高软件测试效率的重要手段,是软件理论和技术发展的重要标志。也是软件测试技术从实验室走向产业的重要标志。软件测试工具是伴随软件测试技术的发展而发展的。目前,应用比较广泛的软件测试工具有下列几种类型:
(1)测试设计工具:测试设计工具有助于准备测试输入或测试数据。测试设计工具包括逻辑设计工具和物理设计工具。逻辑设计工具涉及到说明、接口或代码逻辑,有时也叫做测试用例生成器。物理设计工具操作已有的数据或产生测试数据。如可以随机从数据库中抽取记录的工具就是物理设计工具。从说明中获取测试数据的工具就是逻辑设计工具。
(2)测试管理工具:测试管理工具是指帮助完成测试计划,跟踪测试运行结果等的工具。这类工具还包括有助于需求、设计、编码测试及缺陷跟踪的工具。其代表工具有MI公司的Test Director, Rational公司的Test Manager, Compureware公司的TrackRecord等。
(3)静态分析工具:静态分析工具直接对代码进行分析,不需要运行代码,也不需要对代码编译链接,生成可执行文件。静态分析工具一般是对代码进行语法扫描,找出不符合编码规范的地方,根据某种质量模型评价代码的质量,生成系统的调用关系图等。静态分析工具的代表有Telelogic公司的Logiscope软件,PR公司的PRQA软件,Reasoning公司的Illuma软件。
(4)动态分析工具:动态分析工具与静态分析工具不同,动态测试工具的一般采用“插桩”的方式,向代码生成的可执行文件中插入一些监测代码,用来统计程序运行时的数据。其与静态分析工具最大的不同就是动态分析工具要求被测系统实际运行。其代表有Compuware公司的DevPartner软件、Rational公司的Purify系列产品。
(5)覆盖测试工具:覆盖工具评估通过一系列的测试,测试软件被测试执行的程度。覆盖工具大量的用于单元测试中。例如,对于安全性要求高或与安全有关的系统,则要求的覆盖程度也较高。覆盖工具还可以度量设计层次结构,如调用树结构的覆盖率。如Telelogic公司的TestChecker测试软件。
(6)负载和性能测试工具:性能测试工具检测每个事件所需要的时间。例如,性能测试工具可以测定典型或负载条件下的响应时间。负载测试可以产生系统流量。例如产生许多代表典型情况或最大情况下的事物。这种类型的测试工具用于容量和压力测试。专用于性能测试的工具有Radview公司的WebLoad、,icrosoft公司的WebStress,MI公司的LoadRunner等工具。
(7)GUI测试驱动和捕获/回放工具:这类测试工具可使测试自动执行,然后将测试输出结果与期望输出进行比较。此类测试工具可在任何层次中执行测试:单元测试、集成测试、系统测试或验收测试。捕获回放工具是目前使用的测试工具中最流行的一种。其代表有Rational公司的TeamTest、Robot,Compuware公司的QACenter,MI公司的WinRunner等。
(8)基于故障的测试工具:首先给出软件的故障模型,在此故障模型下,给出基于该故障模型的软件测试工具。这是目前一种有很好发展前景的软件测试工具。随着人们对软件故障认识的不断深入,软件的故障模型也会越来越完备,并更加符合实际。基于故障的软件测试工具有三个需要研究的问题:一是故障模型的准确程度,二是测试的准确程度,三是测试的自动化程度。目前比较典型的是Rational公司的C++测试产品C—Inspector。
1.12  软件测试技术的发展现状
软件测试技术是和程序联系在一起的,自从有了程序,也就有了软件测试。只不过是早期人们没有认识到这个问题罢了。
早在二十世纪五十年代,英国著名的计算机科学家图灵就曾给出了程序测试的原始定义:测试是正确性确认的实验方法的一种极端形式。但在这个时期,程序一般是比较简单的,控制类程序和计算类程序是主要的,程序的规模一般在几百~几千行源代码。程序设计者、编程人员和程序测试者一般都是一个人,测试者可以简单的根据程序的功能对程序进行测试,并简单的根据结果的正确性来决定程序是否有错误。由于程序规模小,一般程序的正确性也不存在大的什么问题。
五十年代以后,随着高级语言的诞生和广泛应用,软件的规模急剧增大,就计算机科学本身来说,操作系统软件、编译软件等一般都在数万行源代码,而且由于这种软件一般都是计算机系统运行的核心,其正确性和可靠性的要求都比较高,传统程序设计的思想和软件不可靠性的矛盾日趋突出。于七十年代诞生的软件工程技术是软件发展的里程碑,它在某种程度上缓解了这个矛盾,但没有从根本上解决问题。
七十年代中期以后,是软件测试技术发展的最活跃的时期。Brooks总结了开发IBM OS/360操作系统中的经验,在著名的《神秘的人—月》一书中阐明了软件测试在研制大系统中的重要意义。1975年,美国黄荣昌教授在论文中讨论了测试准则、测试过程、路径谓词、测试数据及其生成问题,首次全面系统地论述了软件测试的有关问题。Hetzel在1975年整理出版了《Program Test Methods》一书,书中纵览了测试方法及各种自动测试工具,这是专题论述软件测试的第一本著作。Goodenough和Gerhart首次提出了软件测试的理论,从而把软件测试这一实践性很强的学科提高到理论的高度,被认为是测试技术发展过程中具有开创性的工作。此后不久,著名测试专家Howden指出了上述理论的缺陷,并进行了新的开创性工作。以后,Weyuker,Ostrand,Geller和Gerhart等进一步总结原有的测试理论并进一步加以完善,使软件测试成为有理论指导的实践性学科。
在软件测试理论迅速发展的同时,各种软件测试方法也应运而生。黄荣昌提出了程序插装测试技术;Howden在路径分析的基础上,提出了系统功能测试和代数测试的概念;Howden、Clarke和Darringer等人提出了符号测试方法,并建立了DISSET符号测试系统;Demillo提出了程序变异测试方法;Osterweil和Fosdick提出了数据流测试方法;White和Cohen提出了域测试方法;Richardson和Clarke提出了划分测试方法。总之,七十年代至八十年代,是软件测试技术迅速发展的时期,数十种软件测试方法被提出,软件测试技术已迅速发展成为一个独立的学科。
但总体来看,七十年代至八十年代,软件测试技术的研究主要是在理论上。实用的软件测试系统并不多见,少数的测试系统由于测试效率不高,也难以进入市场。
进入二十世纪九十年代,随着计算机技术的日趋普及,软件的应用范围逐步扩大,一些关系到国际民生的行业、关系到国家安全的重要部门已变得越来越依赖软件。软件的规模在大幅度的扩大,软件的复杂性在大幅度的提高,由于软件测试技术的发展远远落后于软件技术的发展,软件不可靠性的矛盾变得更加突出。因此,进入九十年代,软件的质量与可靠性已引起了政府和社会的广泛重视,各种实用的软件测试系统不断涌现,软件测试产品也逐步的进入市场,专门从事软件测试的公司也相继出现,这为保证软件的质量与可靠性奠定了重要基础。进入2000年以来,我国软件测试技术发展极为迅速,全国目前大约有100余家软件评测中心,软件测试的从业人员有数千人,2003年软件测试的产值达到了数亿人民币。
在软件测试技术的学术领域,1982年,在美国北卡罗来纳大学召开了首届软件测试的正式学术会议,之后,该学术会议每两年召开一次,此外,国际上还有软件可靠性会议,从会议的规模和论文的数量与质量上看,从事软件测试技术的人员在大幅度的增加。我国目前虽然没有专门的软件测试的学术组织,但目前在容错计算专业委员会的学术会议上、全国测试学术会议上都能受到大量的软件测试技术的学术论文。2004年8月,在青海省西宁市召开了全国首届软件测试技术研讨会,2007年,将在昆明召开第二届全国软件测试技术研讨会。
可以预测,在未来的时间里,软件测试技术与行业将会得到更快的发展,主要可能的表现包括:软件测试理论更加完善,测试效率更加提高;更实用的软件测试系统将会大量出现;更多的专门从事软件测试与可靠性评估的公司将会诞生。