等待测试之际

xfyuan
·
·
最初发布于 xfyuan.github.io

img

本文已获得原作者( Jorge Manrubia )和 37signals 授权许可进行翻译。原文分享了一个关于 TDD 测试的观点。

【正文如下】

引言

我现在很少先写测试或利用它们来设计代码了。

正文

我最近在 37signals 开始忙于一个新项目上。我们面前一片白纸,空无一物,这意味着我们能快速前进。我发现自己每天都能创建许多 PR。而我想要尽早开启它们以验证讨论时,它们都含有下面这个东西:

img

这只是反映出我常在最后才写测试的工作方式。一个例外是,当测试为我提供了最短的反馈循环时,就我的经验而言,这在基础设施中比在产品环境中更频繁地发生。但即便如此,我也不寻求利用测试来帮我设计系统。我并不践行 TDD(Test-Driven Development)。

我对于 TDD 及其所能带来的都非常了解。我曾完全拥抱这种范式,当它在某时某刻被引爆时,我停止了对它的使用,首先会有一种内疚感,然后则是感到一种解脱

关于 TDD 有这些方面我都很喜欢:它鼓励从外部观察系统,就像一个隐藏了复杂性的黑匣子,提供了一个易于理解的界面。正如我在过去所写的那样,我认为这是一个关键性的设计原则,你需要把它应用在每一个抽象层面上,从 app 的边界之外直到其包含的最后一个内部方法。我认为你根本不需要 TDD 来做到这一点,但从用户的角度考虑接口是积极的。

而从负面的一侧来看,TDD 鼓励一种我对其抱以警惕的测试风格:通过 mock 慢的依赖性来构建非常小而快的测试。在我的经验中,这种测试方案有着糟糕的成本/收益:在达到给定的信心水平之时,它既昂贵又低效。多年以前,我写下了一些关于测试偏好的思考。我可以把其总结为_尽最大可能地测试真实的东西_。

TDD 的另一个危险在于,伴随而来的信念是强调可以独立测试的构建代码块能产生设计良好的系统。我可以相信,一个设计良好的系统在某种程度上必须是可测试的,但我不认为反之亦然或者说每个单独的部分都必须是可单独测试的。你可以构建出一个糟糕的设计,却有着完美的单元测试且上千个用例在不到一秒钟内就跑完。然后,还有一个问题,就是让每个模块都可以在没有依赖性的情况下可测试,这就需要为这些模块的可注入性和间接性付出代价。我相信你可以构建出好或者不好的设计,用或者不用 TDD 均可。我看不出许多人为之辩护的那种坚实因果关系。

但最重要的是,我最不喜欢 TDD 的是你经常看到它缺乏实用主义。它很少作为一种工具在某些情况下使用,而是作为一种设计技术来驱动你如何构建软件。这种介绍,加上 TDD 带来的仪式感,吸引了教条主义者和随之而来的所有负面事物。

TDD 是一个引起从业者和批评者强烈反应的话题。我不做 TDD,但我知道它对很多人都工作良好。只要它没有教条的味道,或者被用作攻击他人专业素养的武器,我就没有问题。我只是把它看作是一个自己不用的工具,仅此而已。

2
评论
登录后评论

适当的测试能够覆盖掉一些底层库升级带来的bug,还是值得的,一个系统上了生产后,不可能不写测试,因为我就有过不写测试的系统上生产的经验,一个rb文件的语法错也会导致生产挂掉,显然也不可接受。至于需要写多少测试来保证生产的稳定性,这其实是一个业务代价问题。

我喜欢 TDD 创始人 Kent Beck 的回答( https://stackoverflow.com/a/153565/518291 ):

我因有效的代码而不是测试而获得报酬,所以我的理念是尽可能少地测试以达到给定的置信度(我怀疑这种置信度与行业标准相比很高,但这可能只是狂妄自大) . 如果我通常不会犯某种错误(比如在构造函数中设置错误的变量),我就不会对其进行测试。我确实倾向于理解测试错误,所以当我有复杂条件的逻辑时,我会格外小心。在团队中编写代码时,我会修改我的策略以仔细测试我们共同容易出错的代码。

基于这种理念,不同的人会有不同的测试策略,但考虑到对测试如何最好地适应编码的内部循环的理解尚不成熟,这对我来说似乎是合理的。十年或二十年后,我们可能会有一个更通用的理论来说明哪些测试要写,哪些测试不要写,以及如何区分。与此同时,实验似乎是有序的。

我发现我也是按这种策略写测试的,如果哪里逻辑很简单,可能不会写测试,而复杂的地方尽可能高的覆盖测试。

社区准则 博客 联系 社区 状态
主题