3.4 测试先行(Test-First)
尽早发现软件缺陷,并采取合理的应对策略,可以降低整个软件的开发成本。如果在进行软件开发时能够首先编写测试代码(Test-First),也就是说在明确要开发某个功能后,首先思考如何对这个功能进行测试,并完成测试代码的编写,然后编写相关的功能代码满足这些测试用例,那么就会迫使开发人员从易用性、易测试性的角度考虑问题,从而定义出清晰的、明确反映意图的模块接口来。另外,为了使得测试能够通过,开发人员就会主动把那些难以测试的耦合(依赖关系)去掉。这样不仅仅是获得了可测试性,而且也产生了更好的设计和系统架构。
3.4.1 测试驱动开发(Test-Driven Development)
Test-Driven Development(TDD)是一种一切软件开发活动都要从首先编写测试代码开始的软件开发过程的应用方法,是敏捷软件开发的推荐做法。
TDD的基本思路就是通过测试来推动整个开发的进程,如图3-3所示,有3个步骤:
图3-3 测试驱动开发
(1)在写功能代码前,先用测试用例将功能需求描述出来。因为此时还没有功能实现代码,所以执行测试用例失败。很多软件界面会用红色信息表示测试失败(红灯)。
(2)编写功能代码,使前面失败的测试用例通过。很多软件界面会用绿色信息表示测试通过(绿灯)。
(3)重构功能代码,改善设计。
重复这些步骤:红灯(测试失败)、绿灯(测试通过)、重构,直至全部功能完成。
因为在编写测试用例时,已经对其功能的分解、使用过程、接口都进行了设计,从而将单元测试变成了设计过程的一部分,同时也展示了功能代码是如何工作的。一定程度上,测试用例变成了功能代码的使用文档,实现“代码即文档”的思想。
当然TDD最重要的功能还在于保障代码的正确性,能够迅速发现、定位问题所在。理论上使用TDD永远不会有未被测试的代码,这也给开发人员重构现有代码和对应用进行回归测试(Regression Test)提供了信心和保障。特别是在程序修改比较频繁时,由于测试用例已经完成,测试期望的结果也是完全可以预料的。
3.4.2 行为驱动开发(Behavior-Driven Development)
Behavior-Driven Development(BDD)是在TDD的基础上发展而来的一种敏捷软件开发的方法。BDD最初是由Dan North在2003年命名,它鼓励软件项目的开发人员、测试人员和非技术人员或商业参与者之间的协作。
BDD作为一种设计方法,本身不是关于测试的,它的重点是客户和技术人员使用几乎近于自然语言的方式(通用语言)描述系统的行为和预期的结果。软件开发中表达不一致是最常见的问题,造成的后果就是开发人员最终做出来的产品不是客户期望的。如果客户(非技术人员)和技术人员使用同一种“语言”来描述同一个系统,则可以最大程度避免表达不一致带来的问题,从而做出符合客户需求的设计。
但是如果光有设计,没有验证的手段,就无法检验实现是不是符合设计,因此BDD还是要和测试结合在一起的。当使用通用语言来描述测试时,可以让任何人更容易地了解被测试的内容。例如,使用“如果银行账户被透支,就不能取款”这样的描述,而不是写一个名为testOverdrawnAccount的测试。
BDD使用用户故事(user story)来描述需求。用户故事通常遵循特定的模板形式:
As a [人/角色] I want [特征/功能] so that [结果/利益]
作为一个[人/角色],我需要[某些特征和功能],以便能得到[相应的利益或结果]。
同样的一个故事,可能会有不同的场景。利用以上的模板描述故事之后,可以再通过以下的模板对不同场景进行描述:
Scenario :标题(描述场景的单行文字) Given [上下文] And [更多上下文] When [事件] Then [结果] And [更多结果]
以一个经典的ATM取款机为例,故事可以描述为:
Story: 银行账户持有人提取现金 As a [银行账户持有人] I want [从ATM机提取现金] so that [不需要在银行柜台排队]
同样的故事,会有不同的场景发生:
Scenario 1: 银行账户有足够资金 Given银行账户有足够资金 And有效的银行卡 And提款机有足够的现金 When账户持有人要求取款 Then银行账户余额应该被扣除 And提款机应该分发现金 And应该退还银行卡
如果银行账户持有人取款的金额比他的存款还多:
Scenario 2: 银行账户透支超过上限 Given银行账户已透支 And有效的银行卡 When账户持有人要求取款 Then应该显示拒绝取款的消息 And提款机应该拒绝分发现金 And应该退还银行卡
如果仔细观察,就会发现Given-When-Then其实定义了一个完整的测试,如图3-4所示。
图3-4 Given-When-Then
下一章介绍的Jasmine就是一种BDD风格的JavaScript测试框架。