测试驱动开发有效吗?

2025-06-07

测试驱动开发有效吗?

介绍

伯特兰·罗素担心的是必须接受某些公理才能继续学习数学,即使这些公理不一定经过严格证明。他在他的《数学哲学导论》一书中探讨了这方面的问题。伯特兰·罗素的“在我们的时代”一集中给出的一个例子是,对于空间中的任意两点,这两点之间都存在一条线。这是直观的,但没有证据证明它的真实性。缺乏证据的一个主要问题是,即使某些东西可能是直观的,也有可能争辩说这件事对你来说并不直观,或者其他答案更直观,并且没有证据可以证明一个论点是对是错。

本文将探讨的一个问题是,我们有任何证据证明测试驱动开发 (TDD) 有效吗?

在这种情况下,“工作”是什么意思?常用的两个衡量标准是:

  • 生产率
  • 代码质量

实践 TDD 真的能提高生产力或代码质量吗?单是衡量生产力或代码质量就已经够难的了。

在这篇文章中,我们将探讨业界围绕 TDD 的一些讨论以及为以科学的方式评估 TDD 所做的一些努力。

业界观点

在我们研究科学研究和数据之前,值得先回顾一下有关 TDD 的一些众所周知的主观讨论以了解背景。

Kent Beck认为在 1999 年左右开发或“重新发现”了TDD。从那时起,TDD 的支持者不断涌现,相关的书籍也层出不穷。业内确实有一群人声称 TDD 对于编写优秀的软件至关重要。

Ruby on Rails的创始人David Heinemeier Hansson (他的名字通常缩写为 DHH)在他的博客文章《 TDD 已死,测试万岁》中表达了一种似乎相当普遍的反对 TDD 的观点。这篇文章的一个有趣之处在于,人们认为 TDD 不知何故被业界公认为正确的开发方式,甚至正在造成危害。这篇文章写于几年前,但其论点似乎并没有太大变化。

就我个人经验而言,TDD 在软件开发中并非普遍接受的必要流程,也很少被强制执行。TDD 的实践者并非被轻视,因此存在诸多争议,但人们普遍认为它并不重要,也未必正确。当然,不同软件团队的情况有所不同,但总的来说,这是我的经验。在我参加的站立会议上,经常听到开发人员说:“我已经完成了,但现在只需要添加测试了。” 在这样的对话中,我从未听到有人建议应该使用 TDD 流程。在大多数情况下,最终还是由开发人员自己决定。

Bob Martin 的观点可能颇具争议,但他却是 TDD 的重要支持者。他在自己的文章《当 TDD 不起作用时》中试图反驳 DHH 的观点。

原始“TDD 已死”帖子中的参考文献是Jim Coplien撰写的文章《为什么大多数单元测试都是浪费》,该文章在Jim Coplien 和 Bob Martin 辩论 TDD 的视频中进行了讨论

TDD 已死这个话题也引发了Kent BeckMartin FowlerDavid Heinemeier Hansson之间的长时间讨论,非常有趣,如果你感兴趣的话可以在这里观看:

这些视频中一个有趣的细节是围绕令人愉快的工作流程的讨论,以及在这个领域是否存在显着的区别,即喜欢编写测试来开始解决问题的思维方式,还是喜欢在已经编写了某种形式的问题解决方案之前不编写测试的思维方式。

以上仅涵盖了业内少数人士的意见,还有很多例子。我之所以在此指出这些,是因为尽管在所有这些博客文章和讨论中都进行了激烈的辩论,但却无法得出确凿的答案。似乎很少有一方能够令人信服。这或许是事物的本质,但或许我们可以更深入地探讨一下。

几乎所有讨论都一致认为自动化测试很重要。大多数分歧似乎都围绕着对 TDD 流程的理解,以及自动化测试的粒度。

与软件开发中的许多主题一样,我们分享和消费的很多关于 TDD 的信息都基于观点和轶事。我们从讲述者的角度听到许多故事,并试图构建一个正确的框架,以便将其应用到我们自己的情况中。我们通常只是尝试一些方法,看看它们是否有效。一些数据会很有用。是不是因为软件开发本身就很难用这种方式衡量?在 TDD 方面,至少已经做出了一些努力来收集数据。

TDD研究

2003年,一项名为《 行业测试驱动开发初步调查》
的研究,以“24名专业结对程序员”为对象,进行了一项研究。其中一组采用TDD进行开发,另一组则采用当时更为传统的“设计-开发-测试-调试”瀑布式开发方法。该研究还引用了一项早期德国研究,该研究以19名研究生为对象,得出的结论是:

测试优先的方式既不会加快开发速度,也不会
提高质量。然而,
以现有接口的合理复用来衡量,程序的可理解性会提高

该项研究存在许多局限性,2003 年的研究正试图解决这些局限性。

根据乔治和威廉姆斯的论文,TDD 小组编写的代码通过了 18% 以上的功能黑盒测试用例,但开发时间却增加了 16%。

本研究的一个假设是,TDD 方法能够生成外部代码质量更优的代码。基于所进行的数据分析,实验结果支持了 TDD 方法能够生成外部代码质量更优的代码的观点。然而,结果的有效性必须结合外部有效性部分所讨论的局限性来考量。

关于对照组缺乏测试,也有一些有趣的发现。不实践TDD似乎导致了总体上缺乏测试的倾向。

这项研究存在诸多局限性,但它仍然在收集一些关于 TDD 在行业中如何运作的真实数据方面取得了良好的进展。至于 TDD 是否有效的证据,这项研究还远远不够。

一篇值得一看的有趣论文是Janzen, DS, (2006)。该论文探讨了其他研究
并对其收集的数据进行了分析。这篇论文篇幅较长,我不会在这里重复太多内容,但我会重点介绍其中的一些有趣的数据和观点。这些数据很有意思,但值得注意的是,这些数据来自 21 世纪初,样本量相对较小。

下表总结了Janzen, DS, (2006)中引用的各篇论文的研究结果

类型(CE)是受控实验,(CS)是案例研究。

在工业领域

学习 类型 公司数量 程序员数量 质量效应 生产力效应
乔治 CE 3 24 TDD 通过的测试增加了 18% TDD 耗时延长了 16%
马克西米利安 CS 1 9 缺陷密度减少50% 最小影响
威廉姆斯 CS 1 9 缺陷密度降低40% 没有变化

在学术界

学习 类型 程序员数量 质量效应 生产力效应
爱德华兹 CE 59 缺陷减少 54%
考夫曼 CE 8 改善信息流 50% 改善
穆勒 CE 19 没有变化,但更好的重复使用 没有变化
潘库尔 CE 三十八 没有变化 没有变化
埃尔多格穆斯 CE 三十五 没有变化 提高生产力

这里的数据表明,TDD 的结果大多是正面或中性的。有一个例外(前面提到的 George 的论文),TDD 的耗时比对照组长 16%,但值得注意的是,对照组在该研究中编写的测试更少。

TDD 作为一种设计方法的本质实际上尚未被研究,但早期的零散采用仅基于传闻证据。

虽然实证研究很少会产生绝对可重复的结果,但此类研究可以提供因果关系的证据,暗示在特定情况下最有可能出现的结果。

我觉得这是一个很好的观点。测量很困难,对于这样的事情,获得​​完全确定的结果几乎是不可能的,但我们仍然可以利用证据来辅助决策。

调查数据显示,开发人员对 TDD 流程的看法随着 TDD 经验的积累而提高,而对最后测试编程的看法则下降。

这篇论文的大部分数据都来自调查。这些调查表明,开发人员在测试和软件开发方面的知识和经验越丰富,就越有可能在 TDD 流程中获得更好的体验。这很有意思,但当然不是什么重大发现。

本文得出的结论是:

这项研究表明,与类似的测试最后方法相比,TDD能够并且很可能以最小的成本提升某些软件质量。尤其是在代码复杂度、规模和测试方面,TDD表现出了统计学意义上的显著差异。

这个结论似乎对 TDD 非常有利。这些研究的一个显著问题是样本量相当小,这使得结果的统计显著性受到质疑。即便如此,我认为这项研究总比没有好,至少能给我们一些参考。

这项研究揭示了初级开发人员和成熟开发人员对 TDD 的接受度和有效性存在许多差异。

对我来说,这只是一个有趣的观察。为什么经验和对 TDD 的接受度之间存在相关性?

类似的研究成果:《测试驱动开发
研究项目与实验
概述》也探讨了各种研究论文。这篇论文发表于 2012 年,内容略新,包含了一些近期的研究。其中一项重要的补充是与 IBM 和 Microsoft 开发团队合作开展的研究。

本研究的最终结论是(Nagappan et al.,2008):

  • 降低缺陷密度(IBM 40%,Microsoft 60% - 90%)
  • 编码特征所需时间增加(15%-35%)。

对研究有效性的威胁被确定为(Nagappan et al., 2008):

  • 使用 TDD 方法的开发人员的积极性更高。
  • 使用TDD开发的项目可能会更容易一些。

该论文的研究结果不如 Janzen 的研究结果积极,因为他们正确地指出,结果差异太大,样本量太小,无法得出任何积极的结论。

2012 年进行的另一项对照实验再次得出结论,TDD 可能是一件好事,但需要更多证据。

2016 年的另一项研究比较了 TDD 与测试最后开发 (TLD) 的效果。

在本文中,我们报告了一项实验
[13] 的复制,其中将 TDD 与测试最后方法进行了比较。

这项研究似乎倾向于得出这样的结论:TDD 并没有比 TLD 带来改善:

鉴于第 5 节中提出的局限性,
TDD 似乎不会提高或降低参与者
在迭代开发技术(
在生产代码之后编写单元测试)方面的表现

如果你观察一下测试是如何进行的,你会发现一个有趣的现象,那就是程序员是如何运用迭代开发的。无论是 TDD 还是 TLD,测试和生产代码之间都有一个相当紧密的循环。或许紧密的迭代循环比测试代码的顺序更重要?

在我看来,这篇论文没有提供足够的数据来得出任何结论。它当然也没有证明 TDD 比在一个相当大的项目中先写完所有生产代码再写测试好还是差。

我们最后要看的研究是我最近偶然发现的一项名为《测试驱动开发过程剖析:先测试还是后测试真的重要吗?》的研究,也是由 Fucci 等人完成的。这项研究似乎得出了与前一项研究类似的结论,只是这次的案例中,参与的程序员来自行业。此外,比较的对象是迭代测试后 (ITL) 开发(我认为这个术语比 TLD 更贴切)和测试驱动开发 (TDD)。

该研究的另一个有趣的结论是,较短的周期时间(生产代码和测试之间的时间)在某种程度上确实可以带来更好的质量。

一些结论

从数据来看,我们很容易得出“TDD 有效吗?”这个问题的答案是不确定的。

如果问题变得更具体,至少会有一些答案。

大量证据似乎都支持较短的迭代测试周期,这与 TDD 文献中提出的方案非常相似,它能够显著提高代码质量,同时最大程度地降低对生产力的影响。使用小规模可测试代码块进行小规模迭代的流程,确实能够提高代码的可维护性。

目前的证据表明,单元测试优于集成和更高级别的测试。

目前几乎没有证据表明实践 TDD 是有害的。

在紧密的迭代周期内,先写测试还是最后写测试更好尚无定论。

测试是一门需要时间学习才能真正受益的学科。这是我自己的观察,但我们研究的一些研究也支持这一观点。

我们真的能确定 TDD 是否真的有效吗?我不知道。积极的一面是,现在这类问题似乎越来越频繁地被提出。正在进行更严谨的研究。以Nicole ForsgrenJez HumbleGene Kim合著的《Accelerate》为例。这本书并非专门讨论 TDD,但它是一个令人惊叹的例子,展现了人们正在努力探索哪些技术在软件开发中真正有效,因此至少我们应该获得更准确的信息来帮助我们做出此类决策。

关于这一切的个人想法

我花了很多时间鼓励其他开发者实践 TDD,或者至少尝试一下。通常情况下,人们会尝试一下,但很难坚持下去。我会试着解释,TDD 需要随着时间的推移不断学习,当你熟练掌握之后,感觉棒极了!

我经常会想,我可能错了。如果我试图让人们花时间去做一些不那么好的事情怎么办?有什么证据证明TDD有效吗?仅仅因为它对我有效,并不意味着它对每个人都有效。

这就是我写这篇文章的原因。我想找到 TDD 确实有效的证据。我也想尽可能多地阅读那些反对 TDD 或反对其某些方面的人的文章。仅仅因为我认为 TDD 很好,我就倾向于避开他们,这并不是一个好的学习方法。

我个人确实认为,TDD 的多种方法都是可以接受的。TDD 的定义不应该像古籍那样,被严格照搬,不可更改。

对我来说,TDD 最大的优势之一(或许是最被低估的优势)在于它所鼓励的设计。我经常听到有人抱怨,过多的单元测试会导致代码难以维护和修改。这只是学习过程中常见的陷阱。一旦你将 TDD 添加到你的软件开发技术库中并熟练掌握它,它应该能够真正帮助你实现优秀的软件设计。如果你的目标是编写优秀、简洁、设计良好的软件,我相信 TDD 能够真正帮助你实现这一目标。

不过,有时确实感觉 TDD 有点太难了。这让我想起用 Java 做函数式编程。如果一切设计从一开始就考虑到 TDD,那其实相当容易。这种情况至今仍然很少见,而且在我们工作的系统中,一直尝试 TDD 确实非常困难。不过,多亏了如今的工具和教学资料,情况似乎正在好转。

尽管存在一些缺点,但读过和体验过之后,我仍然认为 TDD 是一款非常优秀的工具。我会继续使用它,并鼓励其他人也这样做。

参考

George, B., Williams, L., (2003). 行业测试驱动开发的初步调查

Janzen, D., Saiedian, S., (2005). 测试驱动开发:概念、分类和未来方向

Janzen, DS, (2006).测试驱动开发对软件质量影响的实证评估。

Sanchez, JC, Williams, L., Maximilien, M, (2007). IBM 持续使用测试驱动开发实践

Bulajic, A., Sambasivam, S., Stojic, R., (2012). 测试驱动开发研究项目和实验概述。

Causevic, A., Sundmark, D., Punnekkat, S, (2012). 测试设计技术知识对测试驱动开发的影响:一项受控实验

Mäkinen, S., Münch, J., (2014). 测试驱动开发的效果:实证研究的比较分析

Fucci, D., Scanniello, G., Romano, S., Shepperd, M., Sigweni, B., Uyaguari, F., Turhan, B., Juristo, N., Oivo, M., (2016). 使用多站点盲分析方法对测试驱动开发效果进行外部复制

Goto Fail、Heartbleed 和单元测试文化

测试驱动开发 - 维基百科

剖析测试驱动开发流程:先测试还是后测试真的重要吗?Fucci 等,ICSE(2017)

剖析测试驱动开发过程:先测试还是后测试真的重要吗?| 晨报

伯特兰·罗素 - 面对面访谈 (BBC,1959) - YouTube

伯特兰·罗素 - 在我们的时代 BBC 广播 4 - YouTube

伯特兰·罗素(第一部分,共六部分)权威与个人:社会凝聚力与人性 - YouTube

文章来源:https://dev.to/ruarfff/does-test-driven-development-work-p54
PREV
我希望在刚开始学习 React 时就知道的 3 个概念
NEXT
通过玩这个游戏来提升你的 S3 技能!