2008年1月8日星期二

Behaviour Driven Development Intro

看了Dave Astels写的《BDD Intro》,给了我很多观念上的改变。
  1. focus on testing? 原先的Test Driven Development(TDD),即测试驱动开发,很容易给人们以名称上的误解,以为就是先写测试。而实际上程序员写的测试和测试人员的测试还是有很大 的不同,程序员写测试是为了描述程序要实现的功能,从而来指导自己的设计与实现。所以用behaviour来进行描述,更加自然,更加贴近需求。
  2. 单元测试之误。Unit Test,很容易给人一种感觉,即测试方法与实现方法应该一一对应(1-1 relationship)。而BDD可以一次只描述行为的一个方面(we should be thinking about facets of behaviour),比如在某个上下文环境中,方法应该successful,在另一个上下文环境中,方法又应该failed。描述与实现的方法可以一对多,也就是说BDD的粒度比TDD要小。
  3. specifications VS Verification. 应该是说明(用should),而不是证实(用assert)。“说明”是要描述程序功能应该是什么样的,should_be xxx。“证实”是要确保程序正确运行,这里就有点奇怪,我还没有写程序,怎么知道程序运行正不正确呢?当问题比较简单的时候,开发者一般是没意识到的, 因为下意识里,在写测试的时候,已经在想程序的实现细节了。但是当问题比较复杂的时候,有些开发者就不知道该怎么写测试,或者写出的测试也很复杂,甚至写 出的测试本身都有问题。遇到这种情况,就应该把复杂的问题分解。而BDD就是在引导我们分解问题,通过一个个“在什么什么情况下,程序应该怎么怎么样”, 问题很自然很清晰地描述出来了。原先问题是立体的多面体,现在被展开铺平了。然后再把展开的facets放到一个特制的“点钞机”(autotest) 上,它会告诉你接下来该做什么。
  4. 很小,很精干。在TDD的指导下,通过重构,在大多数情况下我们已经可以让实现方法更短小,更简单,更易理解,但如果方法的分支多一点,异常情况多一 点,对应的测试方法往往会膨胀得“很好,很强大”(可能是功力不够,实现方法也没有重构得很彻底)。BDD本身就让我们每次描述专注在行为的某个方面上, 首先就保证了测试简单容易理解。当然在实际用RSpec的时候,往往受以前写单元测试的惯性思维,总想把功能在一个测试里都描述出来,结果有些测试还是写 得比较臃肿。用的是BDD的形,做的却是旧一套的事。看来工具只能起到有限的约束,只有真正经过实践积累,领悟到了工具的良苦用心,观念上转变了,再强迫 做法的改变,正确地用工具,才能事半功倍。
  5. expected, actual. 我以前在写测试的时候,总有某个时候会忘记,在assertEquals()方法的参数列表里,到底哪个排在前面,是expected还是actual? 虽然写反了并不影响功能,因为等式两边可以交换,等式仍然成立。但当测试出错时,打印的出错信息就会让人迷惑。而RSpec里,根本不用去想到底顺序该如 何,actual.should_equal expected,should后面就该接期望值,很自然的事。因为在使用自然语言时,这样的逻辑已经重复了无数遍,已经深入到了潜意识里,根本不用再思维。
  6. 作者在最后很有意思,既然TDD已经成那样了,人们已经理解错了也用错了,何必再费力气去纠正他们呢,干脆另起炉灶,重新树立一个品牌,就叫BDD。
  7. 最后,其实在项目中真正用的是RSpec + RSpec on Rails,RSpec是针对Ruby的,后者才是针对Rails的扩展。

感觉BDD与TDD并不是矛盾的,并不是说BDD就一定比TDD高级先进。TDD与BDD的目的是一样的,都是用来驱动程序的设计与实现的,用来确保程序 实现了预期的功能,它们提倡的小步迭代,更是在持续地纠正你的方向,让你不至于在错误的道路上越走越远。只是TDD被很多开发者误解,没有领会到它的精 髓,没有正确运用,没完全享受到TDD的好处。BDD进行了一些改进,在观念上强迫你按照behaviour的方式思维,在使用上更加接近于自然语言,让 开发者用编程语言写描述就像是在写一句话一样。
对于真正熟练正确运用的开发者,其实TDD与BDD也就是招式的不同。所谓高手,一草一木皆可为剑。

题外话:原来behaviour和behavior都是正确的拼写,类似于colour与color。

没有评论: