paint-brush
为什么我认为 TDD 不是必需的by@shai.almog
1,162
1,162

为什么我认为 TDD 不是必需的

Shai Almog5m2022/11/22
Read on Terminal Reader

测试驱动开发强调单元而不是集成测试。结果可能是质量较低,其中包含产品中存在的错误。
featured image - 为什么我认为 TDD 不是必需的
Shai Almog HackerNoon profile picture


我最近在伦敦 Java 社区做了一个关于调试的演讲。在谈话的问答部分,有人问我关于测试驱动开发的方法。过去,我以更积极的眼光看待这种做法。编写大量测试。这怎么可能是坏的?

但随着时间的推移,我从不同的角度看待它。


我认为它是一个非常有限的工具,具有非常具体的用例。它不适合我构建的项目类型,并且经常阻碍它应该促进的流畅过程。但是让我们回溯一下。我真的很喜欢 这篇将 TDD 中的类型和问题分开的帖子。但让我们稍微简化一下,让我们澄清一下,每个 PR 都应该有良好的覆盖率。这不是 TDD。这只是很好的编程。


TDD 不止于此。在其中,我们需要定义约束,然后解决问题。这种方法是否优于解决问题然后验证约束是否正确?这是 TDD 的核心前提,而不仅仅是编写良好的测试覆盖率。

好的

TDD 是一种有趣的方法。在使用松散类型的语言时,它特别有用。在这些情况下,TDD 非常棒,因为它充当了严格的编译器和 linter 的角色。

在其他情况下它是有意义的。当我们构建一个具有非常明确的输入和输出的系统时。在构建课程和材料时,我遇到过很多这样的情况。在处理真实世界的数据时,当我们有处理数据并以预定义格式输出数据的中间件时,有时会发生这种情况。


这个想法是用中间的隐藏变量来构造方程。然后编码变成了方程式的填充。在这种情况下非常方便。编码变成了填空。

坏人

“测试驱动开发复式簿记。同样的纪律。同样的道理。同样的结果。” – 鲍勃·马丁叔叔


我认为测试有点像复式簿记。是的。我们应该进行测试。问题是我们应该根据我们的测试构建我们的代码,还是相反?这里的答案不是那么简单。


如果我们有一个带有测试的预先存在的系统,那么 TDD 在世界上都是有意义的。但是测试一个尚未构建的系统。在某些情况下它是有道理的,但并不像人们想象的那么频繁。


TDD 的一大亮点是“它的设计”。测试实际上是系统设计,然后我们实施该设计。这样做的问题是我们也无法调试设计。过去,我曾在一家大型日本公司从事过一个项目。该公司拥有最大、最详细的附件设计书籍集之一。基于这些设计规范,公司进行了数千次测试。我们应该用我们的系统通过大量测试。请注意,大多数甚至都不是自动的。


测试有错误。有许多相互竞争的实现,但没有一个在测试中发现错误。为什么?他们都使用相同的参考实现源代码。我们是第一个跳过它并进行洁净室实施的团队。它使代码中的这些错误永久存在,其中一些是严重的性能错误,影响了所有以前的版本。

但真正的问题是进展缓慢。公司无法快速前进。 TDD 支持者会很快评论说 TDD 项目更容易重构,因为测试向我们保证我们不会出现回归。但这适用于事后进行测试的项目。

更糟的是

TDD 主要侧重于快速单元测试。在 TDD 系统上运行缓慢的集成测试或可以在一夜之间运行的长时间运行测试是不切实际的。您如何验证规模和与主要系统的集成?


在理想世界中,一切都会像乐高积木一样卡入到位。我不住在这样的世界里,集成测试严重失败。这些是具有最难跟踪错误的最严重的故障。我宁愿在单元测试中失败,这就是我拥有它们的原因。它们很容易修复。但即使覆盖完美,他们也无法正确测试互连。我们需要集成测试,他们会发现最可怕的错误。


因此,TDD 过分强调“最好有”的单元测试,而不是基本的集成测试。是的,你应该两者兼而有之。但我必须进行集成测试。这些并不完全适合 TDD 过程。

右驱动测试

我根据具体情况以我选择的方式编写测试。如果我遇到提前测试很自然的情况,我会使用它。但在大多数情况下,先写代码对我来说似乎更自然。在编写测试时查看覆盖率数字非常有帮助,这是我在事后做的事情。


正如我之前提到的,我只检查集成测试的覆盖率。我喜欢单元测试和监视那里的覆盖率,因为我也希望那里有良好的覆盖率。但是对于质量,只有集成测试才重要。一个 PR 需要单元测试,我不在乎我们是否在实现之前写了它们。我们应该判断结果。

糟糕的自动化

特斯拉建立其 Model 3 工厂时,它陷入了生产地狱。问题的根源是他们试图使一切自动化。帕累托原则完美适用于自动化。有些事情非常抗拒自动化,并使整个过程变得更糟。


真正失败的一点是在 UI 测试中。 Selenium 等解决方案在测试 Web 前端方面取得了巨大进步。尽管如此,复杂性是巨大的,而且测试非常脆弱。我们最终得到难以维护的测试。更糟糕的是,我们发现 UI 更难重构,因为我们不想重写测试。


我们可能可以跨越 80% 的测试功能,但自动化的收益会递减。在那些环境中,TDD 是有问题的。功能很简单,但构建测试变得站不住脚。

最后

我不反对 TDD,但我不推荐它,实际上我不使用它。当从测试开始有意义时,我可能会这样做,但这并不是真正的 TDD。我根据结果判断代码。 TDD 可以提供很好的结果,但它通常会过分强调单元测试。从长远来看,集成测试对质量更为重要。


自动化很棒。直到它停止。在某种程度上,自动化测试毫无意义。接受这一点并将我们的努力集中在富有成效的方向上,这将为我们节省大量时间和精力。


这是出于我作为喜欢类型安全、严格语言的 Java 开发人员的偏见。由于 JavaScript 和 Python 等语言的灵活性,它们可以从大量测试中受益。因此,TDD 在这些环境中更有意义。


综上,测试还是不错的。 TDD 并没有做出更好的测试。如果它对您有用,那将是一种有趣的方法。在某些情况下,它是巨大的。但是 TDD 是必不可少的,甚至它会显着改进生成的代码的想法是没有意义的。




也发布在这里。