以例为规


原文: SpecificationByExample (译注1)    敏捷        2006年6月16日            Bliki 索引

译注1:以例为规,“例”即测试涉及到的例子,这里主要是指验收测试(Acceptance Testing);“规”即软件规格说明书,以下简称“规格”;“以例为规”即以测试涵盖的例子作为规格,后文也作“范例规格”。



Cedric Beust最近的一篇帖子批评了敏捷方法,引发了一场小规模的博客论战(请看Jeff LangrBob Martin对他观点的反驳)。Cedric的批评之一是针对“测试即为规格”这一观念的,下边这篇Bliki文章虽然是我几年前写的,鉴于与这个话题比较相关,我想它值得用RSS feeder再发一遍。

我参加2002年XP/Agile Universe的一个研讨会时,听到“以例为规”作为测试在 XP中所扮演角色之一的一种描述,这一提法一下子深入进了我的意识里。

(今天再谈“TDD与测试的关系”这个话题实在是跟不上形势了 (译注2),但我和 Jon一样,都觉得TDD(除了驱动设计)还“附送”了一套广覆盖面的自动化测试套件,其价值超过了“副作用” (译注3)这个词所表达的程度。就好比若有人出一百万美元让我登一座山,我可以宣称自己醉翁之意在乎山水之间,但钱包变鼓这个“副作用”的吸引力着实不可小觑也……

我们多数人凭第一感觉理解,所谓规格,应该是全面的,涵盖了所有可能的情况;但范例规格并非如此,范例仅突出所有情况中的一点或几点,要想达到普遍化,需要我们自己推而广之。这也就意味着,在做需求分析时单靠范例规格这一种技术是不够的,但这并非说“以例为规”不能用作捕获需求的首要手段。

要求规格严密详尽,目前占主导地位的思想是利用前置和后置条件,据此得出的规格能明确地判断什么情况通过什么情况不通过。这种技术在规范化的方法中占主导地位,而且是 契约式设计(Design by Contract)的支撑理论。这种技术有可取之处,但并不理想。一些情况下,前置和后置条件写起来很轻松,有时候却非常麻烦。我在几个企业应用开发中尝试过,我发现在很多情况下编写前置和后置条件简直和编写实际工作代码一样困难。而用举例子的方式通常就容易多了——尤其是对那些不懂技术的人来说,毕竟我们编写软件是为了他们,这是以例为规的优势之一。( Timothy Budd曾指出,虽然Stack的许多行为可以用前置和后置条件表示出来,但要描述出它的“后进先出 / LIFO”特性就很需要技巧了。)

TDD有一个重要特性:测试形成了一次复查。其实这“戳穿”了XP社群的一个有趣的小谎,他们一直非常强调“说事情只说一遍” (译注4),事实上他们总是把事儿说两遍:产品代码里说一遍,测试代码里又说一遍。Kent曾指出这条复查原则至关重要,是一条人类随时随地都在实践着的原则。复查的价值很大程度上在于两次分别采用不同的方法。范例规格与产品代码相结合,这样就用完全不同的方式把两件事都说了,也就更有利于发现错误。

在推崇规范化规格的社群,他们很难检验一个设计到底满足没满足规格的要求,尤其因为做检验的是人,而人总是倾向于出错的。然而对于范例规格,检验过程就轻松多了。这是以例为规实践价值大于其理论价值的又一个案例。

一位DbC粉丝指出,如果规格是以测试的形式写的,那么只需针对那些特定的测试输入以硬编码的方式返回输出,这样就满足规格要求了。我尖利地回答说:假如你连这个都担心,那你还有精力去关心规格是用测试还是用DbC来描述的区别吗?——但这儿有个很严肃的问题:测试永远是不全面不完整的,因此不能单单以测试做规格,必须辅以其他机制。不过对我这种头脑喜欢“转圈儿”的人来说,这反倒是以测试做规格的一个优势:既然已明确单以范例做规格还不够,显然就需要做更多工作,通过彻底的沟通交互,确保敲定需求中的每一件事。而以传统的需求分析技术,人们总是想当然地以为把东西写出来了,交互过程也就完成了 ——这真是一个致命缺点。

客户与开发团队不是在打架,双方是合作的工作关系,只有这样,范例规格才能发挥作用。这些范例激发设计团队抽象问题,并起着保证所做出的抽象能有效解决问题的作用。这显然还不够,需辅以更多工作,如经常性的交流沟通、运用 领域驱动设计技术,甚至还需要一定量的DbC工作。尽管我一直没有机会充分全面地使用DbC(即用Eiffel),但我经常以契约角度来考虑接口设计。没错,范例规格很强大,可能是我用得最多的工具了,但绝不是我用的唯一工具。

(如果想找更多以例为规方面的思想,不要囿于是否叫这个名字,可以参考 Brian Marick的文章。他那个站点有一个极好的页面,上面总结了他对这个问题的观点。当然了,找出这个页面并不那么重要,更有价值的是你试着找的过程中所读到的东西。)

(上文原贴出于2004年3月18日。)

可能是受最近博客论战的刺激,Jeff Langr贴出了一个 漂亮的实例,以Java的Math.pow函数为例,通过测试演示范例规格。



译注2:这也是“一场小规模的博客论战”,Dan North先发文“TDD Is Not About Testing”,他认为TDD的重心不在测试,而在驱动开发;之后Jon Tirsén发 文“TDD *Is* About Testing”,按重要性从高到低分别列举了验收测试和单元测试的作用,他认为,虽然两种测试都可以驱动开发,单元测试的最后一个作用才是“在单元层级 驱动设计”,而验收测试的首要作用即“捕获、记录并校对客户的需求”。Jon和Martin两年半前就说谈那些“跟不上形势”了,没想到一年多后 Uncle Bob换了个角度又大谈特谈一番

译注3:原文为“side-effect”,Aslak Hellesoy在对Jon那篇帖子的评论中先用了这个词。无论是“side-effect”还是“副作用”,都常用来表示负面的附带作用,但此处宜理解 为正面效果,即TDD除了驱动设计之外,还附带产生出详尽的测试套件——这些测试(尤其是验收测试)是作为软件规格捕获并验证客户需求的首要技术手段,但 不是唯一手段——此为Martin这篇文章的主题。

译注4:也叫做DRY(Don’t Repeat Yourself)原则。


       

    Ward Cunningham     Robert C. MartinUncle Bob)   Cedric Beust      Jon Tirsén (还记得rBatis和冲浪板的故事吗?)


译后记

敏捷宣言”提出者之一Ward Cunningham创造了Fit(Framework for Integrated Test 集成测试框架),他还是Wiki的发明人。Uncle Bob用Ward发明的瓶子装上Cunningham造的酒,贴上新标签“Fitnesse”,称它为“验收测试框架”。

听到TestNG的作者Cedric Beust公开反对“测试即为规格”,Uncle Bob这样讲:

“Cedric is right that you cannot depend entirely upon tests for the system specification. But he is wrong to case aspersions on the whole discipline of specifying through tests. There is hardly a better way to be unambiguous and current, than to specify tests and require that they always pass.” (Cedric说系统的规格不能完全由测试充当是对的,但他诋毁通过测试明确并验证需求的整条思路就不对了,很难找到比给出测试用例并保持它们全部通过更没有歧义更通行的方法了。)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值