单元测试的七个阶段

这几年了陆陆续续的学习过不少技术,但真正能够对自己的工作起很好帮助的实在不多,测试驱动则是其中之一。前段时间国外有位程序员 Karl Seguin 整理了一篇文章叫做 The 7 Phases of Unit Testing,很快在译言网上也有了翻译《单元测试的七种境界》,作为一位测试驱动开发的粉丝也想借这篇文章整理一下自己的学习过程和体验。

  • 以各种借口拒绝单元测试 Unit Test,比较常用的是“没有足够的时间进行单元测试”

无论是对单元测试的老手还是新手编写单元测试还是有一定得工作量的, 而且单元测试也需要掌握大量的测试框架和工具(光一个 JUnit 或 TestNG 你很难工作地很好)。 所以在这个阶段开发人员往往会觉得单元测试很难写、很费时, 自然而然会使用没有足够的时间进行单元测试的借口,其实在这个阶段开发人员需要积极地学习和掌握测试框架和理解单元测试理念。

  • 尝试单元测试并且立刻开始在自己的博客上鼓吹单元测试和测试驱动开发 Test Driven Development 的好处

开发人员在这个阶段学习很掌握了一些单元测试的工具并在实际工作中加以的运用, 并很好的解决了一些问题,意识到了单元测试的价值。我自己也向同事和同学介绍过相关的技术, 希望大家对相关的技术能很好的学习和运用,现在回想那个时候对单元测试的技术的掌握和理解都是不完整的,只能说是初窥门径而已。

  • 单元测试一切。为了能够完成单元测试,而将私有 private 的方法和属性修改为内部 internal; 为了达到单元测试覆盖率 100% 而测试 getter() 和 setter() 属性(方法)

这样的阶段很明显,特别是遇到 private,static 方法的测试时会感到很麻烦,所以往往采用了一些不优美的解决方式, 目的是能够对相关的方法和类进行单元测试,但没有从根本上意识到是自己的设计有问题, 从而导致可测试性比较差(testability)。至于对 getter 和 setter 方法进行测试到是没有过, 可能只自己所在的公司一直都没有片面的强调过测试100%覆盖率吧。

  • 无法忍受脆弱的单元测试,在没有弄明白是什么的时候,就匆忙转向“集成测试"。

单元测试也是代码,只要是代码就会有设计、编码上共同的问题,比如设计模式的运用、重复代码的问题。 在无法理解和单元测试中“单元”和“隔离”这两个名词的情况下,会想要通过集成测试来实现单元测试。 我自己没有运用过集成测试的工具,但用 dbunit 直接模拟数据库的情况,从而将多个类“集成”起来测试是 这个阶段最常用的单元测试方法。实际上用 dbunit 直接模拟数据库也是非常脆弱和繁琐的,mocking 才是王道。

  • 发现了一种模拟 mocking 框架,并且乐于使用强制语义(strict semantics)。

mocking 是单元测试中不可缺少的重要组成,Java 的单元测试方案中 Easymock 和 Mockit 是两个 成熟的 Mock 框架。但 Mocking 的学习和理解可能是单元测试工具中最具有难度的地方了, 通过运用 Mocking 你会发觉之前很多工作(比如数据库模拟)都是浪费时间、精力和无效的。

  • 模拟 mock 所有可能模拟 mocked 的对象。

通过在单元测试中运用Mocking真正贯彻了单元测试的“单元”和“隔离”的原则,不过Mocking是在件繁琐和困难的事情, 这时候就需要考虑什么是必须要mock的、什么可以不mock的。

  • 开始真正有效单元测试。

恭喜你终于达到了这个阶段,你已经将面向对象设计、设计模式、单元测试、重构等一些技术都融汇到了一起, 你终于可以根据自己的意愿编写真正有效的单元测试了。在这个阶段可能你掌握或有了一套测试框架, 这套测试框架整合了 JUnit、TestNG、Mockit、DBUnit、unitils 等一系列你测试工具使你的编写 单元测试效率是之前的 3-4 倍或者更多。