TDD只是大部分人的美好幻想

前言

在软件开发领域,TDD(测试驱动开发)一直以来都是一个备受争议的话题。有些人将其视为一种敏捷开发方法的基石,认为它能够提高代码质量、加速开发进程,并降低维护成本。然而,也有一些人对TDD持怀疑态度,认为它过于僵化、不切实际,甚至认为它已经过时。

Kent Beck、Martin Fowler、David关于 Is TDD Dead 这个标题引发了人们对于TDD的思考:TDD到底是一种什么样的开发方法?它的优势和局限性是什么?它是否真的适用于所有的项目和团队?本文将深入探讨TDD的现状和未来,以及它在软件开发中的真正意义。本篇文章仅适合对TDD概念有一定了解,且实战过一段时间的读者。

TDD优缺点

这里我总结下TDD的优缺点

优点:

  1. 相对完善的设计: 因为在编写具体代码前全局性思考,编写完善的测试用例,通过测试用例反推验证方案是否可靠
  2. 提早暴露问题: TDD 能够帮助开发者在编写代码之前就发现和修复潜在的 bug,因此可以减少代码中的错误。通过频繁地运行测试用例,可以及时发现并解决问题,避免 bug 的积累。
  3. 提高代码质量: TDD 鼓励开发者在编写代码之前编写测试用例,这样可以更好地考虑代码的设计和实现。通过编写测试用例,开发者可以更早地发现和纠正潜在的问题,从而提高代码质量。
  4. 提高开发者信心: TDD 能够帮助开发者更加自信地进行代码修改和重构,因为他们可以通过运行测试用例来验证代码的正确性。这种自信可以使开发者更加愿意进行代码重构和改进,从而提高代码质量和可维护性

缺点:

  1. 增加开发时间: 编写测试用例需要额外的时间和精力,有时编写单元测试的耗时跟编写实现代码时间55开,甚至可能更大。
  2. 大部分情况下TDD带来的收益是有延时性
  3. 团队适应性差: 采用 TDD 需要团队成员有较高的测试编写能力和质量意识,以及对 TDD 开发流程的认可和理解。如果团队成员缺乏相关经验或者对 TDD 持负面态度,那么很可能会导致 TDD 实施效果不佳。

优点大家应该都很熟悉了,这里我们先看缺点。

增加开发时间

如果你第一次编写单元测试 ,那么你在单元测试 编写的耗时很大概率是超过编写具体实现的代码的时间。这有部分原因来自测试相关的API的不熟悉。通过一段时间的练习,编写单元测试 耗时将会减少很多。但是这并不能保证你把编写单元测试 的耗时比编写具体实现代码的时间少。写过一段时间单元测试的人,特别是以TDD 为模式编写过的人,应该都清楚编写单元测试耗时比具体实现代码高,甚至耗时是其后者的两倍都是常有的事。

如果你在这样一个快速交付、快速迭代的团队中,单元测试 的耗时可能会成为一个挑战。在这样的团队中,时间是宝贵的资源,开发者更倾向于快速地编写和交付功能代码,而不是花费时间编写测试用例。尤其是在团队中已有测试人员的情况下,在项目初期,TDD 提早暴露问题的优势可能并不十分明显。这是因为在需求提交测试之前,团队仍需进行其他测试流程,这些流程已经能够发现大部分常见问题。因此,TDD可能只对那些不易于发现的问题具有优势,例如一些边界情况或复杂逻辑中的潜在问题。

试想下,别人的需求都写了70%,而你还在编写测试用例。当项目经理咨询你进度时,你要如何作答。然后你应用了TDD你的收益又有多少呢?

所以假设你在这种团队中,那么我建议只在一些复杂的需求中,该需求中的边界场景难以复现时采用TDD。

挑战与限制:测试驱动开发(TDD)在处理未知需求时的缺陷

有的人坚持TDD,认为一切需求都要TDD来写,认为TDD就一定要先写单元测试,后写测试没啥意义,认为后写测试时,问题基本都暴露完了。这种思维非常刻板,也会增加自己的内耗。这种观点存在一个误区,即忽视了后期测试的价值和意义。

假设你接手一个自己非常不熟悉的需求时,采用测试驱动开发(TDD)的开发流程会面临一些挑战。因为在这种情况下,我们可能缺乏对需求的深入理解,难以在一开始就设计出完善的模型。这样一来,开发过程中可能会频繁地出现大面积的变化,导致单元测试需要不断地调整甚至重构。

试想下当你TDD到70%的时候,写下一个单元测试,发现之前的方案不太合理需要重构,那大部分单元测试都白写了,你是怎样的心情。

一般情况下,针对这种不熟悉的需求,我们可能会采取另一种策略:首先全面思考设计方案是否能够满足当前需求,然后快速实现,验证方案的可行性。这种方法有助于避免在开发过程中频繁地更改方案,从而减少因需求变化而带来的调整成本。所以在这种场景下,后写测试是不错选择,虽然后写测试的价值不如先写测试,但它仍有价值。

因此,即使采用 TDD 的方式,我们也需要保持灵活性,不断地根据实际情况调整和改进我们的设计和实现。

大部分情况下TDD带来的收益是有延时性

很多情况下通过编写TDD 代码提早修复的bug,你即使不通过TDD 模式编写也会发现。例如需要将时间戳格式化成yyyy.MM.dd的时间格式化的代码,你跑上真机也能快速验证代码是否正确,更别说大部分开发团队都有个测试人员的情况下了,而这时TDD 收益也就相对不多了,这时TDD 还有个可回归性测试的收益。

但是这个收益一般只有在这块地方需要新增功能,或者其他变更的时候,可回归性测试 才充分体现。首先你要为新增的功能编写单元测试,这时写完后,这时验证我这次调整是否破坏了原有功能的时候,我只用运行下测试,就知道答案了。而如果我后期不再负责这块,而去负责了其他模块,而那个模块没有单元测试,那你编写单元测试的大部分收益则由其他人享受了。这个想法有点狭隘,但是假设你所在的团队都不写单元测试的情况下,那你很少能享受到TDD可回归性测试的收益。

所以只有团队内越来越多的人积极采用TDD 并且重视编写单元测试,才能够真正实现TDD的收益最大化。尽管有些的时候TDD带来的收益可能有一定的延时性,但长远来看,它对于项目的成功和团队的效率提升具有重要意义。

而如果在一个大家都不写单元测试的情况下,那么建议根据接手的需求的复杂度和TDD 的优缺点权衡考虑是否要TDD ,如果你接手的需求很复杂,那还是非常建议TDD的。

团队适应性差

TDD 对开发人员的代码设计能力要求比较高,因为它要求开发者在编写代码之前就要考虑代码的结构和设计,以便编写可测试的代码。这需要开发者具备良好的代码设计能力,包括对软件架构、设计模式和代码规范的理解和应用能力。此外,TDD还要求开发者具备良好的单元测试编写能力,能够编写高质量、有效的测试用例来覆盖代码的各种情况和边界条件。

此外单元测试相关的中文资料非常少,特别是TDD 实战中遇到的问题经常需要用到stackoverflow,对于想要实践TDD的团队来说,团队成员可能需要具备一定的英文阅读能力,以便学习和理解国外的相关资料和资源。此外,团队内部可能需要进行针对性的培训和知识分享,以提升团队整体的单元测试编写能力和实践水平。

还有就是TDD 这种测试驱动开发的开发流程并不是每个人都喜欢或适应。有些开发者可能更倾向于传统的开发方式,即先编写功能代码,再编写测试用例进行验证。TDD 要求在编写实际代码之前就要编写测试用例,这种开发模式提供的正反馈太慢,这可能会让一些开发者感到不习惯或不舒服。有些开发者甚至可能会在编写测试用例时产生负面情绪,这可能会成为在团队中推广TDD的阻碍因素之一。

总结

正如最早提出TDD编程原则的Kent Beck所说

Kent Beck: TDD is a question of trade-offs

TDD不是银弹,它是一个权衡问题,你想要TDD这些优点的同时就得接受这些缺点。而想要达到TDD这些优点并不只有TDD才能达到。根据实际需要,合理选择是否TDD,即使采用 TDD 的方式,我们也需要保持灵活性,不断地根据实际情况调整和改进我们的设计和实现,避免陷入盲目追求TDD而忽视实际需求的误区。

相关推荐
布列瑟农的星空4 分钟前
大话设计模式——关注点分离原则下的事件处理
前端·后端·架构
东京老树根1 小时前
Android - 用Scrcpy 将手机投屏到Windows电脑上
android
现在就干1 小时前
Spring事务基础:你在入门时踩过的所有坑
java·后端
该用户已不存在2 小时前
Gradle vs. Maven,Java 构建工具该用哪个?
java·后端·maven
JohnYan2 小时前
Bun技术评估 - 23 Glob
javascript·后端·bun
二闹2 小时前
聊天怕被老板发现?摩斯密码来帮你
后端·python
Wgllss2 小时前
完整烟花效果,Compose + 协程 + Flow + Channel 轻松实现
android·架构·android jetpack
扛麻袋的少年2 小时前
6.Kotlin的Duration类
android·开发语言·kotlin
独自破碎E2 小时前
得物25年春招-安卓部分笔试题1
android
用户298698530142 小时前
# C#:删除 Word 中的页眉或页脚
后端