深度解读测试驱动开发(TDD)

发表于:2017-3-21 11:22

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:码字    来源:51Testing软件测试网采编

分享:
  TDD 要不要做提前设计呢?
  Kent Beck 不做提前设计,他会选一个最简单的用例,直接开写,用最简单的代码通过测试。逐渐增加测试,让代码变复杂,用重构来驱动出设计。在这个需求里,最简单的场景是什么呢? 那就是文件内容为空,输出也为空。
  当然,对于复杂问题,可能要一边写一边补充新的用例,但对于这种简单的题目,基本可以提前就想清楚用什么用例驱动去什么产品代码。大概可以想到如下的用例:
  · "" => ""
  · "he" | "he 1",一个单词,驱动出格式化字符串的代码
  · "he is" | "he 1\r\nis 1",两个不同单词,驱动出分割单词的代码
  · "he he is" | "he 2\r\nis 1",有相同单词,驱动出分组代码
  · "he is is" | "is 2\r\nhe 1",驱动出分组后的排序代码
  · "he is" | "he 1\r\nis 1",多个空格,完善分割单词的代码
  Martin Fowler 的观点是,以前我们写代码要做 Big Front Up Design ,在开始写代码前要设计好所有细节。而我们有了重构这个工具后,做设计的压力小了很多,因为有测试代码保护,我们可以随时重构实现了。但这并不代表我们不需要做提前设计了,提前设计可以让我们可以和他人讨论,可以先迭代几次再开始写代码,在纸上迭代总比改代码要快。
  我个人比较认同 Martin Fowler 的做法,先在脑子里(当然,我脑子不够用,所以用纸画)做设计,迭代几次之后再开始写,这样,我还是会用最简单的实现通过测试,但重构时就有了方向,效率更高。
  回到这个程序,我发现目前的封装不在一个抽象层次上,更理想的设计是:
 
  main() {
  String words = read_file('words.txt')
  String output = word_frequency(words)
  print(output)
  }
  word_frequency(words) {
  String[] wordArray = split(words)
  Map<String, Integer> frequency = group(wordArray)
  sort(frequency)
  return format(frequency)
  }
  这时候,又有两种选择,有人喜欢自顶向下,有人喜欢自底向上,我个人更倾向于前者。
  现在开始,只要照着 红-绿-重构 的循环去做就可以。 大部分 TDD 做不好,就是没有前面的任务分解和列 Example 的过程。 想看 TDD 过程的话,可以参考我之前做的一个直播: TDD hangman in Java 或者如果需要,我也可以录一个这个题目的视频。
  FAQ
  为什么一定要先写测试,后补测试行不行?
  行,但是要写完实现后,马上写测试,用测试来验证实现。如果你先手工测试,把代码都调试好了,再补单元测试,你就会觉得很鸡肋,还增加了工作量。 不管测试先行还是后行都可以享受到快速反馈,不过如果测试先行,你就可以享受另一个好处,使用意图驱动编程减少返工。因为你的测试代码就是产品代码的客户端(调用者),你可以在测试代码里写成你理想的样子(方法名,参数,返回值等),再去实现产品代码,比起先写实现后写测试,前者返工更少。
  刚写了一个测试,还没写实现。明知道运行测试一定会报错,为什么还要去运行?
  其实测试的运行结果并非只有通过与不通过两种,因为不通过时有很多种可能。所以在明知道一定失败的情况下去运行测试,目的是看看是不是报了期望的那个错误。
  小步快走确实好,但真的需要这么小步吗?
  步子迈太大,容易扯着蛋。练习的时候需要养成小步的习惯,工作的时候可以自由切换步子的大小。当你自信的时候步子就可以大点,当你不太自信的时候就可以立即切换到小步的模式。如果只会大步,就难以再小步了。
  测试代码是否会成为维护的负担?
  维护时也遵循 TDD 流程,先修改测试代码成需求变更后的样子,让测试失败,再修改产品代码使其通过。 这样你就不是在维护测试用例,而是在利用测试用例。
  为什么要快速实现?
  其实是用二分查找法隔离问题,通过 hardcode 实现通过测试后,就基本确定测试是没有问题,这时再去实现产品代码,如果测试不通过,就是产品代码的问题。所以小步快走主要是为了隔离问题,也就是你可以告别 Debug 了。
  为什么测试代码要很简单?
  如果一个测试失败了,修复的时候是改测试代码而不是产品代码,那就是测试代码写的不好。 当测试代码足够简单时,如果一个测试失败了,就有足够信心断定一定是产品代码的问题。
  什么时候不适合 TDD?
  如果你是做探索性的技术研究(Spike),不需要长期维护,而且测试基础设施搭建成本很高,那还是手工测试吧。另外还有「可测试性极差的遗留系统」和「使用测试不友好的技术栈」的系统,做 TDD 可能得不偿失。
22/2<12
100家互联网大公司java笔试题汇总,填问卷领取~

精彩评论

  • w_d775
    2017-3-21 14:27:01

    这篇文章写得不错,现在采用TDD模式的太少了,真的太少了

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号