微软的软件测试方法Reply Quote
国内近年来关于软件测试的问题和讨论越来越活跃。但从总体上说交流软件测试技术的多,而探讨软件测试方法的少。这里的“技术”指的是具体的战术问题,比如说如何使用某种工具来解决某一特定测试问题,或者某一类型软件有哪些测试手段等等。而这里的“方法”指的是宏观的战略问题,或者叫方法论,这包括从软件测试的概念或理念,到企业软件质量控制体系;从软件测试的过程,到测试团队的设置及其职责的界定等等。作为测试人员,热衷于“技术”讨论和交流是一件可喜可贺的事。从中可以感觉到软件测试在中国迅速发展的开端和潜力。但是作为企业的管理决策者,是否也应该以同样的热情来思考“方法”问题呢?特别是当一个软件企业的软件测试从无到有,或者当企业已有一定的软件测试的投入,但发现其实效并不显著,甚至由于测试的引入而带来了新的管理上的混乱。这个时候方法论的思考,更有利于发现问题的根源。即便是一个基层的测试人员,当积累了一定的技术经验后,也应该不时从日常的具体工作中走出来,在一个较高层次上进行回顾总结和借鉴,并试着提出一些优化和改进的措施,这无论对专业上还是对事业上的成长都是非常有意义的。微软在软件测试方面有很多值得一提的经验,在此我想以我个人的体会和思考,同大家一同进行一些探讨。
这里有一点须要特别说明,尽管微软的方法已被微软的实践多次证明是成功的,非常有效的,但这并不意味着这些方法在中国的软件企业中有广泛的可行性。一种方法是否可行还受到很多其他因素的影响,比如企业类型(微软是生产平台软件和通用软件产品的企业),企业管理体制,企业文化等等。所以我的目的只是给大家一些思路和借鉴。两类经典的软件测试方法在具体介绍微软的软件测试方法之前,我想首先从概念,或理念的层面上来理解究竟甚么是软件测试,目的是从中导出微软测试方法的理论根源。传统上认为软件测试的方法从总体上分为两类。第一类测试方法是试图验证软件是“工作的”,所谓“工作的”就是指软件的功能是按照预先的设计执行的;而第二类测试方法则是设法证明软件是“不工作的”。提出第一类方法的代表人物是软件测试领域的先驱Dr. Bill Hetzel(代表论著《The Complete Guide to Software Testing》),他曾于1972年6月在美国的北卡罗来纳大学组织了历史上第一次正式的关于软件测试的论坛。他首先在1973年给软件测试一个这样的定义:“就是建立一种信心,认为程序能够按预期的设想运行。Establish confidence that a program does what it is supposed to do. ”后来在1983年他又将定义修订为:“评价一个程序和系统的特性或能力,并确定它是否达到预期的结果。软件测试就是以此为目的的任何行为。 Any activities aimed at evaluating an attribute or capability of a program or system. ”在他的定义中的“设想”和“预期的结果”其实就是我们现在所说的用户需求或功能设计。他还把软件的质量定义为“符合要求”。
第一类测试可以简单抽象地描述为这样的过程:在设计规定的环境下运行软件的功能,将其结果与用户需求或设计结果相比较,如果相符则测试通过,如果不相符则视为Bug。这一过程的终极目标是将软件的所有功能在所有设计规定的环境全部运行,并通过。在软件行业中一般把第一类方法奉为主流和行业标准。1990年的IEEE/ANSI标准将软件测试进行了这样的定义:“就是在既定的状况条件下,运行一个系统或组建,观察记录结果,并对其某些方面进行评价的过程。The process of operating a system or component under specified conditions, observing or recording the results, and making an evaluation of some aspect of the system or component (IEEE/ANSI, 1990 [Std 610.12-1990]”这里所谓“既定的状况”也可理解为需求或设计。尽管如此,这一方法还是受到很多业界权威的质疑和挑战。代表人物是Glenford J. Myers(代表论著《The Art of Software Testing》)。他认为测试不应该着眼于验证软件是工作的,相反应该首先认定软件是有错误的,然后去发现尽可能多的错误。他还从人的心理学的角度论证,将 “验证软件是工作的”作为测试的目的,非常不利于测试人员发现软件的错误。于是他于1979年提出了他对软件测试的定义:“就是以发现错误为目的而运行程序的过程。The process of executing a program or system with the intent of finding errors.” 这就是软件测试的第二类方法,简单地说就是验证软件是“不工作的”,或者说是有错误的。他甚至极端地认为,一个成功的测试必须是发现Bug的测试,不然就没有价值。这就如同一个病人(假定此人确有病),到医院做一项医疗检查,结果各项指标都正常,那说明该项医疗检查对于诊断该病人的病情是没有价值的,是失败的。我并不完全同意这一看法。
第二类软件测试方法在业界也很流行,受到很多学术界专家的支持。大家熟悉的Ron Patton在《软件测试》(中文版由机械工业出版社出版,具说此书是目前国内测试新手入门的经典教材)一书的第10页,有一个明确而简洁的定义:“软件测试员的目标是找到软件缺陷,尽可能早一些,并确保其得以修复。”有些软件企业以Bug数量来作为考核测试人员业绩的一项指标,其实就是接受了这样的方法。两类方法的优劣对比虽然软件测试总的目的是为了软件产品的质量,但很明显这两类测试方法在具体目标、或指导思想上截然相反。由此也决定了它们在思路、过程和测重点上有很大的差别,并各有利弊的。第一类测试方法以需求和设计为本,因此有利于界定测试工作的范畴,更便于部署测试的侧重点,加强针对性。这一点对于大型软件的测试,尤其是在有限的时间和人力资源情况下显得格外重要。而第二类测试方法与需求和设计没有必然的关联,如果计划管理不当,测试活动很容易丢失重点,走入歧途。第一类测试方法可以与软件的架构和软件开发的计划相配合,使软件测试活动逐层次的展开,从而使软件的功能和质量有计划地逐步完善和提高(关于测试的层次问题,我会在今后的讨论中专门介绍)。第二类测试方法不具备这种过程的渐进性。第一类测试方法的缺点是缺乏灵活性,不利于测试人员主观能动性的发挥,正像Myers先生所说,不容易找到软件的错误(Bug)。而这方面正是第二类测试方法的长处。微软的策略正是因为认识到两类测试方法各有利弊,微软在软件测试活动中将两类方法结合起来,以第一类测试方法为基础和主要线索,阶段性地运用第二类测试方法。微软的第一类测试微软的第一类测试总体上说分为三个步骤进行:审核需求和设计—〉设计测试—〉实施运行测试。前文已述,第一类测试是以需求和设计为本来验证软件的正确性。大家很自然的想到,需求和设计本身也有正确性的问题。依据不正确的需求和设计不可能开发出正确的软件产品,测试也将是徒劳的。因此验证需求和设计是微软进行第一类测试的第一步。
有必要指出的是,这里所说的需求和设计具体说来它一般包括:
(1)由项目经理根据用户要求(信息来源于市场部门,用户支持部门等等)而编写的需求文本(Requirement Specification);
(2)由项目经理根据需求文本而编写的功能设计文本(Functional Design Specification);
(3)由开发人员根据功能文本而编写的实施设计文本(Implementation Design Specification)。
微软的测试人员要参与所有这些文本的审核。作为测试人员,审核重点是检查文本对用户需求定义的完整性、严密性和功能设计的可测性。同时这种审核对于测试人员也是一种热身活动,使他们尽早地进入技术和业务状态。第二步,测试人员要根据已审核通过的需求和设计编制测试计划,设计测试用例。在前面提到的三种文本中,功能设计文本是主要依据。原因很简单,这类测试关心的是软件是否能正确地实现功能,而不是这些功能如何被具体实施的。从这里大家可以看出这是典型的“黑盒测试”。确实微软的测试主要是从用户角度进行的黑盒测试。这一步的完成就意味着“测试计划”和“测试用例设计”两个文本的完成。“测试计划” 文本主要阐述测试的范畴、领域、方法、工具、资源和计划时间表等等。“测试用例设计”文本要列出测试用例、每个用例的设置、执行步骤和预期结果。
测试的这两个文本也要被项目经理和开发人员审核。这样经过各种相互的审核,大家对项目形成了基本的共识。第三步的实施运行测试是整个开发过程中最长最复杂的一个阶段。从总体上说就是将上一步设计的测试用例按计划付诸实施的过程。这包括编写自动化测试程序、反复运行自动化测试程序,也包括阶段性执行手动测试用例。这一阶段的测试必须在周密的计划下进行,在前面我已提到,这正是第一类测试的特点和长处。这种计划性首先体现在开发和测试的相互协调配合,根据产品的架构和功能模块的依赖关系,按照项目的总体计划共同推进。从测试的过程来看,总是先运行或执行简单用例,然后再复杂用例;先验证单一的基本功能,再综合的端到端的功能;先发现解决表面的,影响面大的Bug,再深层的,不容易重现的Bug。因此随着项目开发和测试的进程,产品的功能不断完善,质量不断提高。这里有一点要特别指出,有很多测试用例是要反复运行的,特别是基本的自动化测试每一天,每一个 Build上都要运行。
尽管这些测试大多数情况下都是通过的,很少再发现新的Bug,但其价值是显而易见的,就是为了防止质量回归。可见Myers的理论在这里是不适用的。这一阶段测试人员还有一项繁琐但却很重要的工作,就是对已有的测试用例的维护。比如通常以下两种情况下要新增一些测试用例,一是对于当初测试设计不周全的领域,二是对于外部的Bug(比如从Beta客户报告来的),没有被现有测试用例所覆盖。当产品的功能设计出现更改时(在微软这是常事),所涉及的测试用例当然也要相应地修改。微软的第二类测试微软的第二类测试是阶段性的,常常根据需要而带有随机性和突击性。对于这类测试,在微软有一个专门的名称:“Bug Bash(Bug大扫除)”。 Bug Bash通常发生在项目开发各阶段(微软叫里程碑)的末期,比如Beta版发布前,划出一个专门的时间段(通常1-3天),在这期间所有参与项目的人员,集中全部精力,运用各方面的知识,尽全部智慧来搜寻项目的Bug。这是一个非常有意思的活动,但要组织好这样的活动并非易事。
一般有以下要点:
(1)尽管这是一个测试活动,但参与者并不仅限于测试人员。项目经理,开发人员甚至于高层管理人员都应参加,如同全民动员。目的是要集思广益;
(2)要鼓励各部门,领域交叉搜索,因为新的思路和视角通常有助于发现更多的Bug;
(3)为调动积极性,增强趣味性,可以适当引入竞争机制,比如当活动结束时,评出发现 Bug最多,发现最严重Bug的个人,给以物质和精神奖励。
(4)可以分专题展开,比如安全性、用户界面可用性、国际化和本地化等等。
微软的第二类测试除了Bug Bash外,经常还有一些专业性的测试,最典型的是针对安全性攻击测试。一般会邀请公司内部,或业界的专家来搜寻产品的安全漏洞。以上我从传统软件测试概念的角度,介绍了微软的策略和两类传统测试方法的具体做法,及其侧重点。这其实仅仅是一个基础,一个很原始的基础。软件测试在微软软件产品开发中的作用、地位远不是这些原始的方法所能达到的,也不是传统软件测试概念所函盖的。微软在软件测试方面有很多特有的做法,和概念上的突破,比如“软件测试的信息服务功能”、“以用户为中心的宏观质量体系”、“分级测试”、“项目的质量管理系统”、“Bug三方会审”、“测试自动化”和“软件测试的软硬件—部门、团队、人和基础设施”等等。这些我会在以后的讨论中分专题进行介绍。
微软的软件测试方法(二)我在前一篇“微软的软件测试方法”中介绍了微软的两类基本测试方法,其基本思想大家应该是比较熟悉的,因为它们还只是传统的软件测试方法的综合。所以单从形式上,它并没有体现出对传统框架的突破。但是从另一个层面来考察微软软件测试时,你会对一些基本的事实感到惊讶。比如,“微软的测试人员和开发人员数量大致相等或略多”,“微软的产品成本中测试大约占40%以上”等等。人们会有疑问,仅仅是作为功能验证和搜寻Bug的测试能消耗这么大量的资源吗?有必要付出如此大的代价吗?应该有理由相信,微软作为一个软件企业,其每一份投入都是有意义的,因此也可断定微软在软件测试方面的努力一定超出传统测试方法的范畴。
历史回顾为了更好的理解微软件测试在方法和理念上的突破,我想首先回顾一下软件开发和软件测试的发展历史,并从中揭示其必然性。Edward Kit 在他的畅销书“Software Testing In The Real World : Improving The Process(1995, ISBN: 0201877562)”中将整个软件开发历史分为三个阶段:第一个阶段是60年代及其以前,那时软件规模都很小、复杂程度低,软件开发的过程随意。开发人员的Debug过程被认为是唯一的测试活动。其实这并不是现代意义上的软件测试,当然一阶段也还没有专门测试人员的出现。第二个阶段是70年代,这个阶段开发的软件仍然不复杂,但人们已开始思考开发流程问题,并提出“软件工程Software Engineering”的概念。但是这一阶段人们对软件测试的理解仅限于基本的功能验证和Bug搜寻,而且测试活动仅出现在整个软件开发流程的后期,虽然测试由专门的测试人员来承担,但测试人员都是行业和软件专业的入门新手。
第三个阶段是80年代及其以后,软件和IT行业进入了大发展。软件趋向大型化。与之相应,人们为软件开发设计了各种复杂而精密的流程和管理方法(比如 CMM和MSF),并将“质量”的概念融入其中。软件测试已有了行业标准(IEEE/ANSI ),它再也不是一个一次性的,而且只是开发后期的活动,而是与整个开发流程融合成一体。软件测试已成为一个专业,需要运用专门的方法和手段,需要专门人才和专家来承担。
测试与开发的融合在这一历史发展过程中,最值得注意的是测试与开发流程融合的趋势。人们对这种融合也许并不陌生。比如测试活动的早期展开,让测试人员参与用户需求的验证,参加功能设计和实施设计的审核。再比如测试人员与开发人员的密切合作,随着开发进展而逐步实施单元测试、模块功能测试和系统整合测试。的确这些都是测试与开发融合的表现形式,而且初期的融合也只反映在这个层次上。90年代以后,软件的规模和复杂程度迅速提高,这种形式上的融合也迅速走向更深层次,更具实际意义。具体地说这种融合就是整个软件开发活动对测试的依赖性。传统上认为,只有软件的质量控制依赖于测试,但是现代软件开发的实践证明,不仅软件的质量控制依赖于测试,开发本身离开测试也将无法推进,项目管理离开了测试也从根本上失去了依据。在微软,测试的确有这样的地位和作用。这就是为什么微软在软件测试上有如此大的投入。
开发对测试的依赖现代软件开发,特别是大型软件开发通常会遇到以下两个问题:
(1) 在开发初期,如何能够展开大规模团队,群体齐头并进,而同时保持开发的有序性。从而有效利用资源,缩短开发周期。
(2) 在开发后期,如何解决深层次的Bug,如何面对设计更改,而能够保证产品的质量不出现或少出现回落。
对于小型简单的软件,这两个问题也存在,但不突出,而且容易解决。但对于复杂的大型软件的开发,这两个问题常常会成为难以逾越的障碍。通常大型项目的功能丰富,但架构、层次也会相当复杂。稳妥的开发方式是,一次投入少量的人员,逐层开发,逐层稳定。但这种方式显然资源利用率低,开发周期长,不能满足现代软件和IT行业高速发展、瞬息万变的需要。因此大型项目需要大型团队。
在微软,产品开发团队(主要包括开发、测试和项目管理)一般都有百人以上规模,有些产品甚至上几千人(Windows2000的开发部门曾有3000多人)。这样大规模的人力资源作用在一个动态的,内部相互联系的系统中,若没有有效的协同,其混乱是不可避免的。试想,有两个开发人员,分别在开发两个不同的功能模块,其相互有依赖关系。为了相互协调,他们可以随时进行当面讨论。如果这种关系发生在五个开发人员和五个功能模块之间,这种协调就只能通过定期的会议来进行。而一个大型项目,会有许许多多这样的关系,而且很多时候这种关系有着不确定性和不可预见性。当一个开发人员编写一段新的代码或对已有代码进行改动和调整时,他(或她)常常无法确定,或无法完全确定究竟有哪些相关的模块会受到影响,以及在什么请况下这种影响会带来什么结果。因为系统的复杂性已远远超出了人的逻辑思维、技能和经验所能力及的范畴。因此这种传统的协调手段是远不能满足需要的。在微软,这种协调是通过测试来实现的。具体来说就是:每日建造+自动化测试。
关于每日编译和自动化测试,我将来会作专门介绍,这里简单的说就是每天都建造一个新版本,每个版本都要运行通过一定量的自动测试用例,以检验当天工作的质量。这里所说的质量当然有一般意义上质量的概念,但同时它也反映项目在开发过程中的整体协调性。自动测试的最大优点在于它的高度可重复性。一个理想的自动测试系统能够让人随时、方便和迅速的运行大量的测试用例。因此一个开发人员可以通过检查当天的自动测试结果来分析前一天代码的质量(事后检查),也可以在当天存入代码前,先运行自动测试以进一步确保存入代码的质量(事前检查)。
在微软,每日建造都是在午夜开始,完成后紧接着就是全面的自动测试,到早晨上班时间之前就会把结果自动通过e-mail等方式发送出来。开发人员上班后的第一件事往往就是检查测试结果。如果没有问题就会开始新的工作。如果有测试有用例没有通过,开发人员则必须协同测试人员一起立刻找出原因,解决后才能开始新的代码。有时一个小的失误会引起大面积的测试用例失败,很大一部分开发团队会受到影响。为尽量避免这种情况,要求开发人员在存入代码之前先在自己的个人建造版本上运行一定量的自动测试,全部通过后在存入。如开发人员没有按照这样的要求,而擅自存入质量不高的代码而造成大量测试失败,这种不负责任的行为是要受到严厉批评的。
从这一过程可以看出,开发人员依赖测试来保证开发工作的质量,使开发整体地协调地向前推进。当开发进入后期阶段,尽管项目已总体成型,开发人员也会不时遇到一些技术上的挑战。比如一些Bug的解决涉及对项目深层次结构的调整;再比如由于客户反馈的意见造成设计的修改。每一次这样的修改和调整事实上都是对一个稳定系统的破坏,如果处理不当往往一个Bug的修改会生成很多新的Bug,就像一系列联锁的恶性循环。很多项目工期的延误都是这样造成的。要避免或至少将这种破坏减少到最低限度,开发人员首先需要知道这种破坏的影响面。在这里单靠开发人员自身的逻辑思维、技能和经验是远远不够的,自动测试再一次成为一种有效的工具。往往开发人员会制定不止一个方案,对每个方案上都运行一遍同样一套自动测试用例,然后比较结果,选出最佳方案。自动测试在这方面所起的作用不仅在产品的开发过程中,它还延续到产品发布后。产品支持部门在为客户提供应急解决方案时也要依赖自动测试。管理对测试的依赖在微软,软件项目管理的主要线索就是Bug的管理,其中最直接具体的管理活动就是“Bug三方讨论会(Bug Triage)”。
会议一般由项目管理Program Manager(简称PM)来主持,有开发人员和测试人员参加(所以叫三方会议)。会上对每个新生成的Bug进行讨论,并决定(1)是否接受这个Bug;
(2)Bug的严重级别和优先级别;
(3)Bug由谁来负责,是由测试提供进一步详细信息,还是交由开发人员解决,以及大致的解决方案等等。
会议还要对老的Bug检查解决进度。这种讨论会常常会发生争论,要求测试人员具有足够的技术基础和用户经验,来捍卫产品的质量。可以说项目开发到了某一阶段后就是由这种Bug的管理所驱动的。这其中的原动力来自测试。项目管理中一项非常重要但也十分困难的工作是衡量项目的进度,包括判断项目的状态,确定项目是否能预期完成。这方面,测试提供了两个非常重要的参数,一个是Bug数量的趋势,另一个是测试结果的趋势。 Bug趋势就是将每天新生成的Bug数和每天被解决的Bug数标成一个趋势图表。一般在项目的开始阶段新生Bug数曲线会呈上升趋势,到项目中后期被解决 Bug数曲线会趋于上升,而新生Bug数曲线应下降,到项目最后,两条曲线都趋向于零。PM会持续观察这张图表,确保项目健康发展,同时通过分析预测项目 Bug趋于零的时间。在一定的历史经验的基础上分析使用这一图表会得到很多有价值的信息,比如说,可分析开发和测试在人力资源的配比上是否恰当,可以分析出某个严重的Bug所造成的项目质量的波动。每天的自动测试结果同样可以形成类似的图表。它同样非常有助于了解当前项目的质量状况,开发测试进度。由测试产生的这些数据不仅在项目开发过程中为项目管理提供有效的依据,而且也是产品通过发布的必要条件。
在微软,每个产品都要经过评审才能通过发布。前面介绍的几个图表是发布评审的重要内容,如果从图表中发现临评审前还出现过较大的质量波动,评审人员一定会对此提出质疑。因此软件项目管理依赖软件测试提供其基本的管理素材。可以说,现代大型软件开发过程中开发和管理对测试的依赖性是测试与开发流程融合的一个根本因素。从另一个角度看,测试与开发流程融合决不仅仅是简单的时间上的同步,更不是双方空间上的接近,而是这种内在的依存关系的外在表现。开发对测试的这种依赖性对测试和测是人员提出了更高的要求。
在理念上,软件测试已远不仅仅只是软件功能的验证和Bug的搜寻;在具体方法上,自动测试和测试工具的使用已成为基本的要求。在微软,测试不仅使用一些通用的工具,每一个产品还有专门开发的专用工具库,测试的代码量常常超过项目本身的代码量。一个软件企业要提高其软件开发的能力,特别是针对大型软件的大规模的快速开发能力,在测试方面对传统理念和方法进行突破是必要的。微软的实践就是一个很好的印证。