2010年为《程序员》杂志写了一篇《敏捷测试的方法和实践》,我们可以回过头来,看看过去的一年,敏捷测试发生了哪些变化。首先,我做了一个实验,分别打开2010年和2011年的“STAREAST Conference at-a-Glance”,输入Agile,2010年显示10个结果,而2011年显示17个结果,有一个很大的增长,说明敏捷测试越来越引起大家的关注。这只是一个表面的现象,我们还需要真正了解发生了哪些实质性的变化。

举一个例子,《敏捷测试:测试人员和测试团队的实践指南》的作者Lisa Crispin在StarEast 2011上有一个演讲??Agile Testing: After the First Year, What’s Next? 其中提到,我们从传统开发方法转向敏捷方法,由于开发人员掌握了测试驱动开发(TDD,Test Driven Development),而测试人员部分地实现了验收测试和回归测试的自动化,所以我们活下来了,但我们在接下来深入实施敏捷测试时,还会面临新的挑战,甚至要克服更大的困难。当测试人员有了一年的经验,并拥有了敏捷方法的价值观、原则和实践之后,我们还不得不考虑如何不断改进持续的发布、如何有效地管理技术债务、如何对客户的需求有更好的理解,这要求我们掌握更深的敏捷测试技术,例如将“精益(Lean)方法”用于改进敏捷测试的绩效,以及重构自动化测试的设计或脚本以提高投入产出比。

TDD 向ATDD、BDD转化?

以前人们谈到敏捷方法,会谈到TDD或UTDD(Unit TDD),但是究竟有多少个公司在采用TDD方法来写代码?而在采用TDD开发方法的公司中,又有多少程序员在全面使用TDD方法呢?TDD是一个纠结的问题。一方面,TDD的确是一个好东西,先写测试用例、后写代码,保证程序员第一次把代码写对,也彻底解决了代码的可测试性问题,在代码层次上把缺陷的预防做到淋漓尽致。另一方面,多数项目很紧张,不可能给程序员足够时间去实施TDD,程序员对实现有极大兴趣,而对测试缺乏兴趣,多数程序员也不愿意或不会主动去做TDD。这样,TDD实践还存在较大困难,有比较多的争议。我看到一位作者写道:组里头TDD说了3年,据我所知,看完两本TDD名著,并坚持写单元测试的人只有我一个(我组里有开发人员15名)。

为了解决TDD实施不力,在过去一年,越来越多的人关注ATDD,即验收测试驱动开发(Acceptance Test Driven Development)。从2003年开始,人们逐渐实践TDD,而ATDD 是在2007年Lasse Koskela写了一本书《测试驱动:Java开发人员的TDD和ATDD》 ,才开始引起大家的更多关注。从那时算起也有四年了,但在国内,则是近一两年的事。当然,我们可以将TDD和ATDD结合起来使用,形成一种混合的方法模型。TDD和ATDD之间的关系,可以用图1来描述。

图1 TDD和ATDD之间的关系

接着,BDD(行为驱动开发,Behavior Driven Development)也开始大行其道,那BDD是不是“做得比较好的TDD”呢?概念越来越多,概念的界限难以确定,BDD可以看成ATDD的延伸,只是BDD更强调用户的视角、用户的行为,为ATDD注入了“Given,When,Then”这样特定的需求描述语言。2009年,BDD创始人在伦敦发表的“敏捷规格、BDD和极限测试交流”中,对BDD给出了如下定义:

BDD是第二代的、由外及内的、基于拉动的(pull)、多方利益相关者的(stakeholder)、多尺度的、高度自动化的敏捷方法。它描述了一个交互循环,可以具有带有良好定义的输出(即工作中交付的结果):已测试过的软件。

但这个定义看起来还不够好,至少让我们明白起来还有一定的困难。实际上,BDD具有自己特定的“Given,When,Then”行为描述语言,和敏捷的user story极为吻合。所以“Given,When,Then” 行为描述语言才是BDD显著的特征。

TDD在写测试用例时,常常会提出“我们应该先测什么”,然后针对测试的条件来填充代码,而BDD则试图换一种方式去思考问题,即问自己“预期的行为是什么?”,可能会写出结构更好的代码。说到底,BDD更关注客户的需求,通过了解客户的不同行为,对客户的需求有更深刻的理解,从而借助对需求逐渐深入的理解来驱动软件开发。

TDD更重要的价值是其思想,像传统的制造业,一定是先知道产品的质量标准或验收标准之后,才去设计、制造。从这个思想来看,TDD、ATDD和BDD都是一样的。不一样的是其具体的操作方法或实践,我们可以说,ATDD和BDD有一定的进步,但还没有到达完美的地步,还有提升的空间。在未来,首先是如何灵活结合BDD、ATDD和TDD来构成一个测试体系,是一个发展方向;其次,是在BDD、ATDD和TDD根本的、共同的思想基础上,构成一个全新的、更完善的敏捷测试框架。后者的可能性更大。

探索式测试的地位

在过去一两年,在敏捷方法中探索式测试(Exploring Test,ET)也是一个热门话题,甚至有些人想用探索式测试来代替传统的用例测试(case-based test)或脚本测试(scripted test),走向另一个极端。探索式测试是对用例测试的补充,在非敏捷开发方法中也可以使用。只是在非敏捷开发方法中,有较为严格的需求规范和设计文档,有充分的时间去设计足够的测试用例,探索式测试只是作为一种辅助的手段发现一些隐藏很深的缺陷,并成为一种产品学习的工具以完善测试用例。然而,在敏捷测试中,由于迭代快、需求变化相对频繁,缺乏详细的需求描述文档和足够的设计描述文档,探索式测试发挥更大的作用,甚至在新功能测试中发挥决定性的作用。需要提醒的是,在敏捷测试中,回归测试应该仍然以用例测试为主,可以这样说,回归测试还是百分之百的用例测试。

探索式测试,实际早在1984年由James Bach和Cem Kaner提出来,但为什么直到近几年才比较热呢?这主要得益于敏捷开发方法的兴起,而敏捷开发方法的兴起又得益于互联网应用的迅速扩张。大家都知道,互联网应用越来越普遍,竞争越来越激烈,迫切要求互联网应用产品发布要快,再加上许多互联网产品的开发,都极具创新性、摸着石头过河,其需求不明确,要求开发周期短,频繁发布新的版本,及时获得市场和用户的反馈,不断修正以更好地满足用户的需求。针对被测对象,所掌握的信息不够充分的情况下,探索式测试是一种很有效的测试方法。而且,把测试过程写下来(脚本化)需要时间,在敏捷测试中,时间显得更为珍贵。如果需求变化快,脚本化的测试用例维护成本也过高、甚至是极大的浪费。探索式测试的倡议者还认为,测试执行过程应该是智力活动的过程,这一过程越善于思考、越流畅,我们越有机会发现缺陷。而用例测试方法,有太多的停顿、不够流畅,会破坏这一过程。

在敏捷测试中,当我们没有清晰的可参照文档、没有机会创建测试,我们自然会采用探索式测试。在James A.Whittaker 的《探索式软件测试》出版之后,探索式测试再次被推向高潮,人们觉得有更多成熟的探索方法可以使用,例如:卖点测试法、破坏测试法、地标测试法、收藏家测试法、极限测试法、超模测试法、深巷测试法、配角测试法、强迫症测试法、取消测试法、通宵测试法、混票测试法。

但探索式测试缺乏良好的系统性、复用性,而且有些探索执行终被证明是没有价值的。而我们关注有价值的探索式测试,将它们记录下来,使之成为固定的测试用例,用于将来的(后继的迭代周期)回归测试。回归测试验证已有功能是否正常运行,需要良好的系统性和很高的覆盖率,确保发布产品的质量,而且回归测试是不断重复的,在极有限的时间内完成越来越多的测试任务,这需要自动化执行、高效率执行回归测试。而这一切,依赖于相对稳定的测试用例。概括起来,敏捷测试可以看成:新功能的(手动)探索式测试 + 脚本化(基于测试用例的)自动回归测试。

敏捷测试的自动化

没有自动化,没有持续集成,也没有敏捷。在敏捷测试中自动化测试更加迫切,这一点比较容易理解,每个迭代(如Scrum中的Sprint)都在增加新的功能,而迭代周期的时间相对固定,随着时间的推移,已实现的功能越来越多,这要求越来越多的回归测试在时间相对固定的周期内完成。如果没有自动化测试,这是不可能完成的任务。

在过去一年中,敏捷测试的自动化又发生了哪些变化?如何重构自动化测试脚本以提高产出投入比(ROI)?下面简单讨论一下敏捷自动化测试框架和敏捷测试工具等内容。

敏捷测试对测试工具要求简单、实用,随时可用,而对敏捷测试来说,自动化测试框架更为重要,它将负责集成各种测试工具,包括单元测试工具和验收测试工具等,还负责与持续集成、缺陷管理系统等整个开发环境集成。作为敏捷测试的自动化框架,一般会选择轻量型、开放类型的框架。说到这种类型的框架,可以参考RobotFramework(http://code.google.com/p/robotframework/)。在近一年,其版本发布比较频繁,也日渐成熟。RobotFramework是基于Python开发的、可扩展的框架,所以适用于多种接口的复杂软件(如用户接口、命令行、Web Service、编程接口等)的测试。适合敏捷测试的框架还有Thoughtworks Mingle + Cruise + Twist,它能帮助测试人员和开发人员敏捷项目管理和协同工作、持续集成、测试自动化,允许使用BDD开发模式和Groovy动态语言来编写测试脚本,包括手动和自动方式来创建可复用的自动化测试脚本,并结合测试领域特定语言(DSL)实现自动化测试。无论是RobotFramework,还是Twist,它们都支持Selenium 2.0,这也反映了Selenium在敏捷自动化测试中的重要地位。当然,敏捷测试也可以采用类似Selenium 2.0+ WebDriver +PushtoTest那样的组合框架。

敏捷测试工具很多,但对敏捷测试来说,我们更要关注能够适应ATDD或BDD的测试工具,如Cucumber、RSpec、NBehave /CBehave /JBehave、EasyB、JDave等。也可以结合先前熟悉的测试工具开展工作,例如用自己熟悉的WatiN来结合SpecFlow 完成BDD模式的自动化测试。采用传统的微软Visual Studio也是可以的,因为在其 2010版本中,增强了对敏捷测试的支持,包括:

发布了Scrum流程模板Visual Studio Scrum 1.0;
支持“测试优先”的开发,支持ATDD;
TDD的插件TestDriven.NET。
敏捷测试管理

基于敏捷测试的管理,更多体现了基于需求测试和基于风险测试的平衡。对于新功能测试,不仅采用探索式测试,还要考虑基于需求的测试方法,借助类似BenderRBT这样的工具,进行需求的因果分析,建立其判定表并进行优化,从而建立非常高效的测试用例,使敏捷测试跟上开发的节奏成为可能。但整个测试周期,包括跨迭代周期的回归测试,都需要对测试风险进行有效的评估,在效率和质量上达到平衡,以保证所发布的产品的质量。

敏捷测试的管理,一定不要急躁、不要急于求成,要循序渐进获得改进,特别是从相对传统的测试方法转型到敏捷测试的团队来说,更要逐渐转型,如同敏捷方法本身所追求的“小步快跑”式迭代,这种转型本身也应被视为迭代过程,而不是突然某个早上,一切都变了。在敏捷测试管理中,不要试图通过一个迭代解决所碰到的各种问题,而是一个迭代只解决一两个问题,随着时间的推移,踏踏实实地、逐步地解决各个问题,即进入一个良性的循环,终解决各种问题,使团队转型成功,无论在测试效率和质量上获得质的飞跃。

在敏捷测试管理中,尽管有比较多的原则要支持,例如“以人为本、为客户创造价值、面对面的沟通、简单化、响应变化和享受乐趣”等,但重要的是以下几个方面。

持续的质量反馈:在整个开发过程中,持续关注质量,关注用户需求,发现任何阶段性成果的问题,持续向产品经理、开发人员等提供质量反馈。
持续改进测试方法,不断学习新方法和提高测试技术能力,不仅和开发人员保持技术同步,而且团队成员能力保持同步成长,想方设法把工作做到。
让团队具有很高的自我组织能力,每个成员都积极主动工作,自己能够解决自己的问题。
让我们享受敏捷测试的乐趣,享受成功!