跳转至

引论

第 1 章

引 论

软件开发的最基本要求是按时、高质量地发布软件产品,而软件测试是软件质量保证的最重要的手段之一。对于软件,不论采用什么技术和什么方法来进行开发,软件产品中仍然或多或少地会存在错误和问题。采用先进的开发方式和较完善的开发流程,可以减少错误的引入,但是不可能完全杜绝软件中的错误,这些引入的错误需要通过测试来发现。

在整个软件生命周期中,每个阶段、每个时刻都存在软件测试活动,软件测试伴随着软件开发,以检验每一个阶段性的成果是否符合质量要求和达到预先定义的目标,尽可能早地发现错误并及时地修正。

1.1 软件测试的必要性

软件无处不在,人们在不同的场合都有可能会不知不觉地使用软件,如日常生活中的手机、智能冰箱、新一代的数字彩电、洗衣机等。人们在日常使用软件中,也或多或少会碰到一些不愉快的事情,如信号显示不对、数据不完整、操作不灵活等。例如,2002 年 7 月,首都机场由于软件缺陷影响通信传输,造成航班无法起飞,大批旅客滞留机场。还有,2008 年北京奥运会官方网站第二阶段开始售票,短短不到半个小时,由于性能问题不能承受过多的同时上线购票,造成网站瘫痪,不得不停止服务。但软件问题有时引起的麻烦远不止这些,造成的危害可能会非常严重。有时仅仅因为软件系统中存在一个很小的错误,却带来了灾难性的后果。下面所介绍的软件质量事故,都是曾经发生的真实故事,它们阐述了一个简单而又非常重要的命题 —— 软件测试的必要性。

1.1.1 迪士尼并不总是带来笑声

1994 年圣诞节前夕,迪士尼公司发布了第一个面向儿童的多媒体光盘游戏 “狮子王童话”。尽管在此之前,已经有不少公司在儿童计算机游戏市场上运作多年,但对迪士尼公司而言,还是第一次进军这个市场。由于迪士尼公司的著名品牌和事先的大力宣传及良好的促销活动,结果,市场销售情况非常不错,该游戏成为父母为自己孩子过圣诞节的必买礼物。但结果却出人意料,当年 12 月 26 日,圣诞节后的第一天,迪士尼公司的客户支持部电话开始响个不停,不断有人咨询、抱怨为什么游戏总是安装不成功或没法正常使用。很快,电话支持部门就淹没在愤怒家长的责问声和玩不成游戏孩子们的哭诉之中,报纸和电视开始不断报道此事。

后来证实,迪士尼公司没有对当时市场上的各种 PC 机型进行完整的系统兼容性测试,只是在几种 PC 机型上进行了相关测试。所以,这个游戏软件只能在少数系统中正常运行,但在大众使用的其他常见系统中却不能正常安装和运行。

1.1.2 一个缺陷造成了数亿美元损失

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

\[ (4 1 9 5 8 3 5 / 3 1 4 5 7 2 7) \times 3 1 4 5 7 2 7 - 4 1 9 5 8 3 5 \]

如果答案是 0,就说明该计算机浮点运算没问题。如果答案不是 0,就表示计算机的浮点除法存在缺陷。

1994 年,英特尔奔腾 CPU 芯片就曾经存在这样一个软件缺陷,而且被大批生产出来卖到用户那里,最后,英特尔为自己处理软件缺陷的行为道歉并拿出 4 亿多美元来支付更换坏芯片的费用,可见,这个软件缺陷造成的损失有多大!

这个缺陷是美国弗吉尼亚州 Lguchbny 大学的 Thomas R. Nicely 博士发现的。他在奔腾 PC 上做除法实验时记录了一个没想到的结果。他把发现的问题放到因特网上,随后引发了一场风暴,成千上万的人发现了同样的问题,以及得出错误结果的其他情形。万幸的是,这种情况很少见,仅在进行精度要求很高的数学、科学和工程计算中才会导致错误。大多数进行财会管理和商务应用的用户根本不会遇到此类问题。

这个故事不仅说明软件缺陷所带来的问题,更重要的是说明对待软件缺陷的态度。

结果舆论大哗。因特网新闻组充斥着愤怒的客户要求英特尔解决问题的呼声。得到这个教训之后,英特尔在网站上报告已发现的问题,并认真对待客户在因特网新闻组上的反馈意见。

比英特尔公司损失更大的是美国丹佛市的国际机场。丹佛新国际机场希望被建成现代的 (state-of-the-art) 机场,它将拥有复杂的、计算机控制的、自动化的包裹处理系统,而且还有 8530km 长的光纤网络。不幸的是,在这个包裹处理系统中存在一个严重的程序缺陷,导致行李箱被绞碎,居然自动包裹车会一直开着往墙里面钻。结果,机场启用推迟 16 个月,使得预算超过 32 亿美元,并且废弃这个自动化的包裹处理系统,使用手工处理包裹系统。

1.1.3 火星探测飞船坠毁

火星探测飞船坠毁是 20 世纪末发生的悲剧,而这主要就是由于软件测试没做好。仅仅由于两个测试小组单独进行测试,没有进行很好沟通,缺少一个集成测试的阶段,结果导致 1999 年美国宇航局的火星探测飞船在试图登陆火星地面时突然坠毁失踪。质量管理小组观测到故障,并认定出现误动作的原因极可能是某一个数据位被意外更改。什么情况下这个数据位被修改了?又为什么没有在内部测试时发现呢?

从理论上看,登陆计划被设计成这样 —— 在飞船降落到火星的过程中,降落伞将被打开,减缓飞船的下落速度。降落伞打开后的几秒钟内,飞船的三条腿将迅速撑开,并在预定地点着陆。当飞船离地面 1800m 时,它将丢弃降落伞,点燃登陆反推进器,借助反推力来不断降低速度,从而可以使飞船能缓缓降落地面。

美国宇航局为了省钱,简化了确定何时关闭推进器的装置。为了替代其他太空船上使用的贵重雷达,在飞船的脚上装了一个廉价的触点开关,在计算机中设置一个数据位来关掉燃料。很简单,飞船的脚不 “着地”, 引擎就会点火。不幸的是,质量管理小组在事后的测试中发现,当飞船的脚迅速摆开准备着陆时,机械震动在大多数情况下也会触发着地开关,设置错误的数据位。设想飞船开始着陆时,计算机极有可能关闭推进器,而火星登陆飞船下坠 1800m 之后没有反推进器的帮助,冲向地面,必然会撞成碎片。

为什么会出现这样的结果?原因很简单。登陆飞船经过了多个小组测试。其中一个小组测试飞船的脚落地过程,但从没有检查那个关键的数据位,因为那不是这个小组负责的范围;另一个小组测试着陆过程的其他部分,但这个小组总是在开始测试之前重置计算机、清除数据位。双方本身的工作都没什么问题,就是没有合在一起测试,其接口没有被测,而问题就在这里,后一个小组没有注意到数据位已经被错误设定。

1.1.4 更多的悲剧

新浪科技引用《商业周刊》网站在 “网络安全” 专题中的文章,对 “冲击波” 计算机病毒进行了分析。2003 年 8 月 11 日,“冲击波” 计算机病毒首先在美国发作,使美国的政府机关、企业及个人用户的成千上万的计算机受到攻击。随后,冲击波蠕虫很快在因特网上广泛传播,中国、日本和欧洲等国家也相继受到不断的攻击,结果使十几万台邮件服务器瘫痪,给整个世界范围内的 Internet 通信带来惨重损失。

制造冲击波蠕虫的黑客仅用了三周时间就制造了这个恶毒的程序,“冲击波” 计算机病毒仅仅是利用微软 Messenger Service 中的一个缺陷,攻破计算机安全屏障,可使基于 Windows 操作系统的计算机崩溃。该缺陷几乎影响当前所有微软 Windows 系统,它甚至使安全专家产生更大的忧虑:独立的黑客们将很快找到利用该缺陷控制大部分计算机的方法。随后,微软公司不得不紧急发布补丁包,修正这个缺陷。

软件缺陷还会造成更大的悲剧,导致生命危险,下面就是两个典型的实例。

1. 放射性设备治死 4 个人

由于放射性治疗仪 Therac-25 中的软件存在缺陷,导致几个癌症病人受到非常严重的过量放射性治疗,其中 4 个人因此死亡。一个独立的科学调查报告显示:即使在加拿大原子能公司 (Atomic Energy of Canada Limited, AECL) 已经处理了几个特定的软件缺陷,这种事故还是发生了。造成这种低级而致命的错误的原因是缺乏软件工程实践,一个错误的想法是软件的可靠性依赖于用户的安全操作。

2. 28 名美国士兵死亡

美国爱国者导弹防御系统是主动战略防御 (即星球大战) 系统的简化版本,它首次被用在第一次海湾战争对抗伊拉克飞毛腿导弹的防御作战中,总体上看效果不错,赢得各界的赞誉。

但它还是有几次失利,没有成功拦截伊拉克飞毛腿导弹,其中一枚在沙特阿拉伯的多哈爆炸的飞毛腿导弹造成 28 名美国士兵死亡。分析专家发现,拦截失败的症结在于一个软件缺陷,当爱国者导弹防御系统的时钟累计运行超过 14h 后,系统的跟踪系统就不准确。在多哈袭击战中,爱国者导弹防御系统运行时间已经累计超过一百多个小时,显然那时系统的跟踪系统已经很不准确,从而造成这种结果。

1.2 为什么要进行软件测试

为什么要进行软件测试?答案很简单,就是为了保证软件质量。1.1 节中所介绍的软件质量事故就说明了这一点,没有很好地完成软件测试任务,产品的质量得不到保证。如果没有软件测试,就不能了解软件产品的质量。测试是软件工程中不可缺少的一部分,特别是当软件无处不在、越来越贴近人们的生活和工作的时候,软件测试的必要性就越来越明显。

对于软件来讲,总会存在或多或少的问题。在需求定义中会出现问题,在软件设计和编程中同样会存在问题。软件系统在构造过程中,不论采用什么技术和什么方法,软件问题仍然不可避免。采用成熟的编程语言、先进的开发方式、完善的开发过程,可以减少错误的引入,但是不可能完全杜绝软件中的错误,这些引入的错误需要测试来找出,软件中的错误密度也需要测试来进行评估。

软件测试是软件质量保证的关键步骤。美国质量保证研究所对软件测试的研究结果表明:越早发现软件中存在的问题,开发费用就越低;在编码后修改软件缺陷的成本是编码前的 10 倍,在产品交付后修改软件缺陷的成本是交付前的 10 倍;软件质量越高,软件发布后的维护费用越低。另外,根据对国际著名 IT 企业的统计,它们的软件测试费用占整个软件工程所有研发费用的 \(50\%\) 以上。

自有程序设计的那天起,测试就一直伴随着软件开发过程。测试是所有工程学科的基本组成单元,自然也是软件开发的重要组成部分。软件测试在产品开发中占据着相当重要的位置,也是软件行业几十年的实践所证明的一个道理,其中也包含从大量的质量事故教训中所获得的教训和经验。以微软公司为例,大家可以感觉到,微软以前的产品 (如 Windows 95 和 Windows 98) 时时会发生崩溃、死机等现象,而今天的产品 (如 Windows 7 和 Windows8) 则比多年前的产品功能要强大得多,稳定性不仅没有下降,反而好得多。为什么呢?这是因为微软公司重视测试工作,在测试上投入比较大,微软总共拥有一万多名专业的测试人员。其次,测试人员越来越有经验,测试流程也越来越规范,测试工作也就越有效。正是由于清晰地认识到了软件测试的重要性,微软的产品质量才有了明显的提高。

最初,微软公司与大家一样,认为测试不重要,重要的是开发人员。通常,一个团队中有几百个开发人员,但只有几个测试人员,并且开发人员的待遇要比测试人员高很多。经过多年的实践后,微软公司发现,去修正那些出现问题的产品所花的钱,比多聘用几个测试人员的费用要高得多,所以,开始不断地聘用测试人员。同时,现在测试人员的待遇和开发人员的待遇非常接近,测试人员水平越高,找到软件问题的时间就越早,软件就越容易更正,产品发布之后越稳定,公司赚的钱也越多。这也是多数软件公司慢慢悟出来的道理,软件测试是软件产品开发中最重要的几个环节之一。

1.3 什么是软件测试

在购买商品时,会发现商品上贴有一个 “QC” 标签,这就是质量检验 (Quality Control)。软件测试,就好比制造工厂的质量检验,是对软件产品和阶段性工作成果进行质量检验,力求发现其中的各种缺陷,并督促缺陷得到修正,从而控制软件产品的质量。所以,软件测试是软件公司致力于提高软件产品质量的重要手段之一。但要给软件测试下个定义,可能不是一件容易的事情。必须了解软件测试学科形成的过程,理解软件测试的正反两个方面的含义,分析软件测试的不同观点,最终给出软件测试一个完整的定义。

1.3.1 软件测试学科的形成

在早期软件开发过程中,软件开发等于编程,软件工程的概念和思想还没有形成,也就没有明确的分工,软件开发的过程随意、混乱无序,测试和调试混淆在一起,没有独立的测试,所有的工作基本都是由程序员完成,一面写程序,一面调试程序。直到 1957 年,软件测试才开始区别于调试,作为一种发现软件缺陷的独立活动而存在。但这时,测试的活动往往发生在代码完成之后,测试被认为是一种产品检验的手段,成为软件生命周期中最后一项活动而进行。在这一时期,测试的投入还很少,也缺乏有效的测试方法,所以,软件产品交付到客户那里,仍然存在很多问题,软件产品的质量无法保证。

1972 年,软件测试领域的先驱 Bill Hetzel 博士 (代表论著《软件测试完全指南》, The Complete Guide to Software Testing, 1993), 在美国的北卡罗来纳大学 (University of North Carolina) 组织了历史上第一次正式的关于软件测试的会议。从此以后,软件测试开始频繁出现在软件工程的研究和实践中,也可以认为,软件测试作为一个学科正式诞生了。在 1973 年,Bill Hetzel 正式为软件测试下了一个定义: “软件测试就是为程序能够按预期设想运行而建立足够的信心”。Bill Hetzel 觉得原先的定义不够清楚,理解起来比较困难,所以在 1983 年将软件测试的定义修改为: “软件测试就是一系列活动,这些活动是为了评估一个程序或软件系统的特性或能力,并确定其是否达到了预期结果”。在上述软件测试定义中,至少可以看到以下几点。

在此之后,软件测试有了很大的发展,不仅制定了国际标准 (IEEE/ANSI), 而且和软件开发流程融合成一体。软件测试是软件开发不可缺少的一部分,由独立的团队承担相应的工作,在软件企业举足轻重。软件测试也逐渐形成一门独立的学科,在许多大学里开设相应的专业或课程,越来越获得学术界的关注。

1.3.2 正反两方面的争辩

Bill Hetzel 可以说是软件测试的奠基人,但他的观点还是受到业界一些权威的质疑和挑战,其中代表人物要数 Glenford J. Myers (代表论著《软件测试的艺术》,The Art of Software Testing, 1979)。Myers 认为测试不应该着眼于验证软件是工作的,相反,应该用逆向思维去发现尽可能多的错误。他认为,从心理学的角度看,如果将 “验证软件是工作的” 作为测试的目的,非常不利于测试人员发现软件的错误。因此,1979 年他给出了软件测试的不同的定义:“测试是为了发现错误而执行一个程序或者系统的过程”。从这个定义可以看出,假定软件总是有错误的,测试就是为了发现缺陷,而不是证明程序无错误。发现了问题说明程序有错,但如果没有发现问题,并不能说明问题就不存在,而是至今未发现软件中所潜在的问题。

从这个定义延伸出去,Myers 认为,一个成功的测试必须是发现了软件问题的测试,否则测试就没有价值。这就如同一个病人 (因为是病人,假定确实有病), 到医院去做相应的检查,结果没有发现问题,那说明这次医疗检查是失败的,浪费了病人的时间和钱。Myers 提出的 “测试的目的是证伪” 这一概念,和 Bill Hetzel 的观点 “测试是试图验证软件是正确的” 针锋相对,为软件测试的发展指出了不同的努力方向,产生了新的软件测试理论和方法。

Myers 的定义是引导人们证明软件是 “不工作的”,以反向思维方式,不断思考开发人员理解的误区、不良的习惯、程序代码的边界、无效数据的输入以及系统的弱点,试图破坏系统、摧毁系统,目标就是发现系统中各种各样的问题。

人类的活动具有高度的目的性,建立适当的目标具有重要的心理作用。如果测试目的是为了证明程序里面没有错误,潜意识里就可能不自觉地朝这个方向去做,在进行测试的过程中,就不会刻意选择一些尽量使程序出错的测试数据,而选择一些常用的数据,测试容易通过,而不容易发现问题。如果测试的目标是要证明程序中有错,那我们会设法选择一些易于发现程序错误的测试数据,这样,测试的结果会更有意义,对软件质量的提高会有更大的帮助。

1.3.3 软件测试的定义

Glenford J. Myers 的软件测试定义,虽然受到业界的普遍认同,但也存在一些问题,例如:

除此之外,Glenford J. Myers 的软件测试定义还强调测试是执行一个程序或者系统的过程,也就是说,测试活动是在程序代码完成之后进行,而不是贯穿整个软件开发过程的活动,即软件测试不包括软件需求评审、软件设计评审和软件代码静态检查等一系列活动,从而使软件测试的定义具有局限性和片面性。

Bill Hetzel 的软件测试定义可能使软件测试活动的效率降低,甚至缺乏有效的方法进行测试活动。但是,Bill Hetzel 的软件测试定义也得到了国际标准的采纳,例如,在 IEEE 1983 of IEEE Standard 729 中对软件测试下了一个标准的定义:使用人工或自动手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求或是弄清预期结果与实际结果之间的差别。这里明确地提出了软件测试是以检验是否满足需求为目标。

这正反两方面的观点是从不同的角度看问题,一方面通过测试来保证质量,另一方面又要改进测试方法和提高软件测试的效率,两者应该相辅相成。因为测试不能证明软件没有丝毫错误、不能确认所有的功能可以正常工作,所以测试要尽可能找出那些不能正常工作、不一致性的问题。软件测试就是在这两者之间获得平衡,但对于不同的应用领域,两者的比重是不一样的。例如,国防、航天、银行等软件系统,承受不了系统的任何一次失效,因为这些失效都完全有可能导致灾难性的事件,所以强调前者,以保证非常高的软件质量。而一般的软件应用或服务,则可以强调后者,质量目标设置在 “用户可接受水平”, 以降低软件开发成本,加快软件发布速度,有利于市场的扩张。

在 SWEBOK 3.0 (2014 年发布的软件工程知识体系) 中,将软件测试定义为 “从一个通常是无限的执行域 (集合) 中选择合适的、有限的测试用例,对程序所期望的行为进行动态验证的活动过程”。这个定义让我们关注期望的行为,即用户的期望,而且这个定义也揭示了测试具有一定的采样特性,只能完成无限操作的集合中一个子集的验证工作,通常无法进行百分之百的测试,测试总是有风险的。这里还强调测试是对程序行为的动态验证,而把静态验证,主要是评审活动,归为 “质量管理”。这里的 “软件测试” 可以说是狭义的软件测试,而广义的软件测试是包含静态测试 (静态验证) 和动态测试 (动态验证), 而且测试中的静态验证也只局限于对需求 (文档)、设计 (文档) 和代码的验证,即局限于对产品的验证。而在一些国际标准中,验证的范围更大,包括评审、分析和测试。这里的评审不仅包含对产品的评审,而且包含对流程评审、对管理评审和对技术的评审。这里的测试和 SWEBOK 3.0 是一致的,属于动态验证,带有一定 “试验” 的性质,不包括评审。

1.3.4 软件测试的其他观点

前面已给出软件测试的定义,但是为了更好地全面理解软件测试,还可以从其他的观点来分析软件测试,其中最突出的观点就是风险的观点和经济的观点。因为没有办法证明软件是正确的,软件测试本身总是具有一定的风险性,所以软件测试被认为是对软件系统中潜在的各种风险进行评估的活动。从风险的观点看,软件测试就是对风险的不断评估,引导软件开发的工作,进而将最终发布的软件所存在的风险降到最低。基于风险的软件测试可以被看作是一个动态的监控过程,对软件开发全过程进行检测,随时发现不健康的征兆,发现问题、报告问题,并重新评估新的风险,设置新的监控基准,不断地持续下去,包括回归测试。这时,软件测试可以完全看作是软件质量控制的过程。

测试的风险观点也可以不断提醒我们,在尽力做好测试工作的前提下,工作有所侧重,在风险和开发周期限制上获得平衡。首先评估测试的风险,每个功能出问题的概率有多大?根据 Pareto 原则(也叫 80/20 原则),哪些功能是用户最常用的 \(20\%\) 功能?如果某个功能出现问题,其对用户的影响又有多大?然后根据风险大小确定测试的优先级。优先级高的功能特性,测试优先得到执行。一般来讲,针对用户最常用的 \(20\%\) 功能(优先级高)的测试会得到完全地、充分地执行,而低优先级功能的测试(另外用户不常用的 \(80\%\) 功能)就可能由于时间或经费的限制,测试的要求降低、减少测试工作量。

上面的叙述,也体现了测试的经济观点,所以测试的风险观点和经济观点有着千丝万缕的关系。测试的经济观点就是以最小的代价获得最高的软件产品质量,正是风险观点在软件开发成本上的体现,通过风险的控制来降低软件开发成本。经济观点也要求软件测试尽早开展工作,发现缺陷越早,返工的工作量就越小,所造成的损失就越小。所以,从经济观点出发,测试不能在软件代码写完之后才开始,而是从项目启动的第一天起,测试人员就参与进去,尽快尽早地发现更多的缺陷,并督促和帮助开发人员修正缺陷。软件测试的经济学观点,可以从 Boehm 的著作《软件工程经济》(Software Engineering Economics,1981) 中得到进一步的印证。

1.4 测试和开发的关系

在著名的软件瀑布模型中,如图 1-1 所示,软件测试是处在 “编程” 的下游、在 “软件维护”

的上游,先有编程、后有测试,测试的位置很清楚。在瀑布模型中,测试只有等到程序完成了才可以执行,强调测试仅仅是对程序的检验。从这里可以看出,Glenford J. Myers 的软件测试定义是从瀑布模型出发的。但瀑布模型属于传统的软件工程,存在较大的局限性,与软件开发的迭代思想、敏捷方法存在冲突,也不符合当今软件工程的实际需求。

需求分析是在软件开发的最前端,也就说明它对后期的影响最大,所以说,软件需求分析很重要,

8db5eec0aeb8aa20f1f0ec92d50b11290fb9cafe009e93e602664997a718d414.jpg

要想成功开发一个软件产品,首先要做好需求分析。但另一方面,在需求分析时,往往很难做到彻底弄清楚用户对产品的各项具体的要求。由于大多数使用或将要使用计算机产品的用户,不是计算机方面的专业人员,甚至对计算机一点都不了解,所以对计算机能做哪些事情、不能做哪些事情、善于做哪些事情、不善于做哪些事情等都不清楚,只能给出软件的一般性功能或目标要求,不能提出具体的要求,也不能给出规范的、科学的、详细的输入和输出需求。这也是为什么一直强调做好需求验证,软件测试人员从项目启动的第一天就要介入,认真对待需求评审。

现在人们普遍认为软件测试贯穿着整个软件生命周期,从需求评审、设计评审开始,测试就介入到软件产品的开发活动或软件项目实施中。测试人员借助于需求定义的阅读、讨论和审查,不仅发现需求定义的问题,而且可以了解产品的设计特性、用户的真正需求,确定测试目标,准备用例 (Use Case) 并策划测试活动。同理,在软件设计阶段,测试人员可以了解系统是如何实现的、构建在什么样的运行平台之上等各类问题,这样可以衡量系统的可测试性,检查系统的设计是否符合系统的可靠性要求、是否存在单点实效的严重问题等。说明软件测试和软件开发在整个软件开发生命周期中交互协作,自始至终一起工作,共同致力于同一个目标 —— 按时、高质量地完成项目。

V 模型,说明软件测试活动和项目同时启动,软件测试的工作很早就开始了,避免了瀑布模型所带来的误区 —— 软件测试是在代码完成之后进行。在 V 模型中,就相对能够准确地反映测试与开发之间的关系,如图 1-2 所示,左边是软件定义和实现的过程 (包括分析、设计和编程), 右边是对左边所构造的东西进行验证的过程,测试与开发有一对一的关系。测试的工作 (右边) 是对开发工作 (左边) 成果的检验,以确认是否满足事先的定义和要求。

V 模型从左到右描述了基本的开发过程和测试行为,非常明确地标注了测试过程中存在的不同类型的测试,并且清楚地描述了这些测试阶段和开发过程期间各阶段的对应关系,即从 4 个层次完成软件的验证,即对需求、系统架构设计、详细的产品设计和代码的验证。

444fb32ff31f6e4ab0f333d140ead11186a609022ac338d06abde5dcb65c8e6e.jpg

也就是说,如果只在某一两个方面 (如代码测试、功能测试) 完成对软件产品的测试,都说明测试是不完整的。只有从这 4 个层次完成对软件产品的测试才是完整的。在第 4 章还会讨论 W 测试模型,进一步了解测试与开发的关系。

1.5 测试和质量保证的关系

任何形式的产品都是过程执行得到的结果,因此对过程进行管理与控制是提高产品质量的一个重要途径。软件质量保证 (Software Quality Assurance,SQA) 活动是通过对软件产品有计划地进行评审和审计来验证软件是否合乎标准的系统工程,通过协调、审查和跟踪以获取有用信息,形成分析结果以指导软件过程。

SQA 部门在新项目的需求分析阶段就开始介入,对形成的软件需求进行分析与评价,并提出可能存在的问题,诸如安全性、可靠性、可扩展性、易用性等,并根据软件本身特性、规模及将来的运行环境等进行综合评定,确定软件要满足的质量要求,记录下来形成正式文档,尽可能对软件周期各个阶段的测量确定一个定量或定性的标准,作为以后各阶段评审的标准和依据。

从这里可以看出,SQA 与软件测试之间相辅相成,既存有包含又存有交叉的关系。SQA 指导、监督软件测试的计划和执行,督促测试工作的结果客观、准确和有效,并协助测试流程的改进。而软件测试是 SQA 重要手段之一,为 SQA 提供所需的数据,作为质量评价的客观依据。它们的相同点在于二者都是贯穿整个软件开发生命周期的流程。它们的不同之处在于 SQA 是一项管理工作,侧重于对流程的评审和监控,而测试是一项技术性的工作,侧重对产品进行评估和验证。

1.6 测试驱动开发的思想

在目前比较流行的敏捷方法 (如极限编程、Scrum 方法等) 中,提出了 “测试驱动开发 (Test Driven Development, TDD)”—— 测试在先、编码在后的开发方法。TDD 有别于以往的先编码后测试的开发过程,而是在编程之前,先写测试脚本或设计测试用例。TDD 在敏捷方法中被称为 “测试第一的开发”, 而在 IBM Rational 统一过程 (Rational Unified Process, RUP) 中被称为 “测试第一的设计”。所有这些,都在强调 “测试先行”, 使得开发人员对所写的代码有足够的信心,同时也有勇气进行代码重构。

TDD 具体实施过程,如图 1-3 所示。在打算添加某项新功能时,先不要急着写程序代码,而是将各种特定条件、使用场景等想清楚,为待编写的代码先写一段测试用例。然后,利用集成开发环境或相应的测试工具来执行这段测试用例,结果自然是失败。利用没有通过测试的错误信息反馈,了解到代码没有通过测试用例的原因,有针对性地逐步地添加代码。为了要使该测试用例通过,就要补充、修改代码,直到代码符合测试用例的要求,获得通过。测试用例全部执行成功,说明新添加的功能通过了单元测试,可以进入下一个环节。

1f9aaadeab9b9acc62776edadffc99b6dbdcaad762c599f6f0e280723233867f.jpg

TDD 从根本上改变了开发人员的编程态度,开发人员不能再像过去那样随意写代码,要求写的每行代码都是有效的代码,写完所有的代码就意味着真正完成了编码任务。而在此之前,代码写完了,实际上,编程工作没有结束,因为单元测试还没执行,其中会发现许多错误,等待去修正。测试驱动开发在于先想好各种应用场景、前提条件,促进开发人员思考,写出更完善的代码,提高工作效率。其次,也确保测试具有独立性,不受实现思维的影响,确保测试的客观、全面。最后,也确保所有代码的可测试性,每一行代码得到了测试,确保代码的质量。

测试驱动开发一改以往的破坏性测试的思维方式,测试在先、编码在后,更符合 “缺陷预防” 的思想。这样一来,编码的思维方式发生了很大的变化,编写出高质量的代码去通过这些测试,在写每一行代码时就要确保能通过测试。测试,也从以前的破坏性的方法转移到一种建设性的方法中来。在这种积极心态的影响下,开发人员的工作效率会有很大的提高,降低开发成本,提高程序的质量。

小结

本章主要讨论下面几个问题:

从讨论的结果中得知,没有测试,软件就没有质量;测试没做好,软件问题可能会引起灾难或给软件企业带来巨大的损失。软件测试是软件质量保证的重要手段之一,是软件开发过程中不可缺少的部分。软件测试,不仅要检验软件是否已正确地实现了产品规格书所定义的系统功能和特性,而且要确认所开发的软件是否满足用户真正需求的活动。软件测试无法证明软件是正确的,总是存在风险的,这就规定了软件测试人员要尽可能地发现软件问题。从这个意义上看,软件测试是为了发现缺陷,而且要尽早地发现缺陷。

通过对软件测试的风险观点和经济观点的分析,可以更好地理解软件测试。通过 V 模型,可以更客观地、更准确地描述软件测试和软件开发的关系。软件测试贯穿着整个软件生命周期,和软件开发构成相辅相成的关系。软件测试驱动开发方法再次昭示了测试的重要性,对提高软件质量、降低软件开发成本有很大帮助。

思考题