乐者为王

Do one thing, and do it well.

100%代码覆盖率的悲剧

英文原文:http://labs.ig.com/code-coverage-100-percent-tragedy

有趣的是,我对测试的观点正在发生变化。十五年来,我一直在宣扬TDD(测试驱动开发,或者被称为测试先行方法),或至少让开发者写些单元测试。不过,最近我发现自己更经常地说,“你为什么要写测试?”而不是“你应该写测试”。

怎么回事?

在办公室四处走走时,开发者要求我帮助他进行单元测试。看来他在使用Mockito测试以下代码时遇到了麻烦:

initialise-method

我想他是非常惊讶于我的回应:“你不需要测试。”

“但我不得不测啊!”他说。“否则如何知道这段代码是正常的?”

“这段代码很明显。没有条件,没有循环,没有转换,没有任何东西。它们只是一些普通的旧式胶水代码。”

“但没有测试,任何人都可以来修改和破坏这段代码呀!”

“看,如果那个虚构的邪恶/无知的开发者来了,破坏了这些简单的代码,如果相关的单元测试中断,你认为他会做什么?他只会删除它。”

“但是如果非要写测试怎么办?”

“在这种情况下,我将这样写测试:”

initialise-test

“但是你没有使用Mockito啊!”

“那又怎么样呢?Mockito没有帮助你。恰恰相反:它会妨碍你,并且它也不会使测试变得更易读或更简单。”

“但是我们决定使用Mockito进行所有测试!”

我:“……”

后来我碰到他,他自豪地说,他已经设法用Mockito写了测试。我明白让测试代码正常运行的心理满足感,但尽管如此,这种解决方案让我难过。

另一个例子

我加入的某个开发团队,他们对新应用程序的高代码覆盖率以及对BDD(行为驱动设计)的新发现感到兴奋。查看代码,可以发现如下的Cucumber测试:

cucumber-test

如果你以前使用过Cucumber,你就不会震惊于它所需的支持代码的数量:

cucumber-support

cucumber-support2

和所有要测试的代码:

cucumber-code

是的,一个简单的地图查找。我和这个开发者有足够的信任去直言不讳地说,“这是在浪费时间。”

“但我的老板希望我能为所有的类写测试,”他回答。

“代价是什么?”

“费用?”

“无论如何,这些测试与BDD无关。”

“我知道,但是我们决定使用Cucumber进行所有测试”

我:“……”

我明白按照自己意愿改造工具的心理满足感,但尽管如此,这种解决方案让我难过。

悲剧在哪里?

悲剧是两位聪明的开发者(我需要带他们去团队面试)浪费时间写那种测试,测试是毫无意义的,但需要后来的IG开发者维护。

悲剧是不使用正确的工具,因为没有特别好的理由,我们决定坚持不懈地使用错误的工具。

悲剧是一旦某个“良好实践”成为主流,我们似乎就忘记它是怎么来的,它的好处是什么,最主要的是,使用它的代价是什么。

如果我们只是机械地应用它而没有太多的思考,这通常意味着我们最终得到最平庸的结果,失去大部分的好处,但支付所有(甚至更多)的成本。根据我的经验,编写好的单元测试并非易事。

那么100%的代码覆盖率值得追求吗?

是的,每个人都应该实现它……在一个项目中。我认为你必须用极端的手段去了解限制是什么。

我们已经有了一个极端的大量经验:0个单元测试的项目,所以我们知道在这上面工作的痛苦。我们通常缺乏的是在另一个极端的经验:强制100%代码覆盖率和一切都是TDD的项目。单元测试(尤其是测试先行方法)是一个非常好的实践,但我们应该学习哪些测试是有用的,哪些是适得其反的。

要记住没有什么是免费的,没有什么是银弹。使用工具前请停下来想一想。

关于作者

Daniel Lebrero在IG的大数据团队担任技术架构师。拥有超过15年的Java经验和4年的Clojure经验,他现在是函数式编程的大力倡导者。可以在TwitterLinkedIn或者他的个人博客找到他。

Comments