it-swarm.cn

测试驱动开发的缺点?

采用测试驱动设计我会失去什么?

仅列出否定数;不列出以否定形式写的福利。

191
IanL

几个缺点(我并没有声称没有任何好处 - 特别是在编写项目的基础时 - 它最终会节省大量时间):

  • 大量投资。 对于简单的情况,你失去了大约20%的实际实现,但对于复杂的情况,你会失去更多。
  • 额外的复杂性。 对于复杂情况,您的测试用例难以计算,我建议在这种情况下尝试使用在调试版本/测试运行中并行运行的自动参考代码,而不是最简单情况的单元测试。
  • 设计影响。 有时设计在开始时并不清晰,随着你的进展而发展 - 这将迫使你重做你的测试,这会产生很大的时间损失。在这种情况下,我建议推迟单元测试,直到你对设计有所了解为止。
  • 连续调整。 对于数据结构和黑盒算法,单元测试将是完美的,但对于倾向于改变,调整或微调的算法,这可能会导致人们可能声称不合理的大量时间投资。因此,当您认为它实际适合系统并且不强制设计适合TDD时使用它。
124
Adi

如果你想做“真正的”TDD(阅读:首先用红色,绿色,重构步骤测试),那么当你想测试集成点时,你还必须开始使用模拟/存根。

当您开始使用模拟时,一段时间后,您将需要开始使用依赖注入(DI)和控制反转(IoC)容器。要做到这一点,你需要为所有东西使用接口(它们本身有很多陷阱)。

在一天结束时,你必须编写更多代码,而不是只用“普通老方法”。您还需要编写接口,模拟类,一些IoC配置和一些测试,而不仅仅是客户类。

请记住,测试代码也应该得到维护和保养。测试应该像其他所有内容一样可读,并且编写好的代码需要时间。

许多开发人员并不十分清楚如何做到这些“正确的方法”。但是因为每个人都告诉他们TDD是开发软件的唯一真正方式,他们只是尽力而为。

这比人们想象的要困难得多。通常使用TDD完成的项目最终会得到许多人们无法理解的代码。单元测试经常以错误的方式测试错误的东西。并且没有人同意一个好的测试应该是什么样子,甚至不是所谓的大师。

所有这些测试都使得“更改”(与重构相反)系统的行为变得更加困难,而简单的更改变得太难和耗时。

如果您阅读TDD文献,总会有一些非常好的例子,但通常在现实生活中,您必须拥有用户界面和数据库。这是TDD变得非常困难的地方,大多数消息来源都没有提供好的答案。如果他们这样做,它总是涉及更多的抽象:模拟对象,编程到接口,MVC/MVP模式等,这需要大量的知识,并且......你必须编写更多的代码。

所以要小心......如果你没有一支热情的团队,至少有一位经验丰富的开发人员知道如何编写好的测试,并且知道一些关于良好架构的知识,那么在走向TDD之前你必须要三思而后行。

184
Thomas Jespersen

当您达到大量测试的程度时,更改系统可能需要重新编写部分或全部测试,具体取决于哪些测试因更改而失效。这可能会将相对快速的修改变成非常耗时的修改。

此外,您可能更多地基于TDD而不是实际上优秀的设计原则开始做出设计决策。虽然您可能有一个非常简单易用的解决方案,无法测试TDD需求的方式,但您现在拥有一个更复杂的系统,实际上更容易出错。

66
Eric Z Beard

我认为对我来说最大的问题是“进入它”需要大量的时间。我仍然处于TDD之旅的开始阶段(如果你感兴趣的话,请参阅我的 博客 更新我的测试冒险)我真的花了 小时 开始。

让你的大脑进入“测试模式”需要很长时间,编写“可测试代码”本身就是一项技能。

TBH,我恭敬地不同意 Jason Cohen的评论 关于公开私人方法,这不是它的意思。 我在新的工作方式上没有比以前更多的公共方法 。但它确实涉及架构更改,允许您“热插拔”代码模块,使其他所有内容更容易测试。您应该 not 使代码的内部更容易访问。否则我们会回到原点,一切都是公开的,那里的封装在哪里?

所以,(IMO)简而言之:

  • 思考所花费的时间(即实际上是测试)。
  • 知道如何编写可测试代码所需的新知识。
  • 了解使代码可测试所需的体系结构更改。
  • 提高你的“TDD-Coder”技能,同时努力提高我们光荣的编程工艺所需的所有其他技能:)
  • 组织代码库以包含测试代码,而无需拧紧生产代码。[。_____。]

PS:如果你想要积极的链接,我已经问过并回答了几个问题,请查看我的 个人资料

54
Rob Cooper

在我练习测试驱动开发的几年里,我不得不说最大的缺点是:

把它卖给管理层

TDD最好成对完成。首先,当您 _知道_ 如何编写 if/else 语句时,很难抵制编写实现的冲动。但是一对会让你完成任务,因为你让他完成任务。可悲的是,许多公司/经理并不认为这是对资源的良好利用。当我有两个需要同时完成的功能时,为什么要为两个人写一个功能付费呢?

将它卖给其他开发者

有些人对编写单元测试没有耐心。有些人为他们的工作感到自豪。或者,有些就像看到复杂的方法/功能从屏幕末端流出。 TDD并不适合每个人,但我真的希望如此。这将使那些继承代码的可怜灵魂更容易维护东西。

维护测试代码和生产代码

理想情况下,只有在做出错误的代码决策时,您的测试才会中断。也就是说,你认为系统是单向运行的,结果却没有。通过打破测试或一小组测试,这实际上是个好消息。您知道 确切地说 您的新代码将如何影响系统。但是,如果您的测试写得不好,紧密耦合,或者更糟糕的是,生成( cough VS Test),那么维持测试可以很快成为合唱团。并且,经过足够的测试开始导致他们正在创建的感知价值的更多工作,那么当计划被压缩时,测试将是第一个被删除的东西(例如,它变得紧缩时)

编写测试以便覆盖所有内容(100%代码覆盖率)

理想情况下,如果您遵循该方法,您的代码将默认100%经过测试。通常情况下,我认为最终代码覆盖率高达90%。这通常发生在我有一些模板样式架构,并且测试基础时,我试图偷工减料而不测试模板自定义。此外,我发现当我遇到一个以前没有遇到的新障碍时,我有一个学习曲线来测试它。我承认用旧的skool方式编写一些代码行,但我真的很想拥有100%的代码。 (我想我在学校里是一个成功者,呃skool)。

然而,有了这个,我会说TDD的好处远远超过了简单的想法的负面影响,如果你能够实现一套覆盖你的应用程序的一套好的测试,但是不是那么脆弱,以至于一次改变就会破坏它们,你会能够像第1天那样在项目的第300天继续添加新功能。所有尝试TDD的人都认为这是他们所有错误代码的神奇子弹,所以他们认为它可以工作,期间。

我个人发现,使用TDD,我编写了更简单的代码,如果某个特定的代码解决方案能够正常工作,我花费更少的时间进行辩论,并且我不必担心更改任何不符合条件的代码行。团队。

TDD是一门难以掌握的学科,我已经学习了几年,而且我一直都在学习新的测试技术。这是一项巨大的时间投资,但从长远来看,您的可持续性将远远超过您没有自动化单元测试。现在,如果只有我的老板可以解决这个问题。

49
casademora

在您的第一个TDD项目中,有两大损失,时间和个人自由

你失去了时间因为:

  • 创建一个全面的,重构的,可维护的单元和验收测试套件,为项目的第一次迭代增加了大部分时间。从长远来看,这可能会节省时间,但同样可以节省您的时间。
  • 您需要选择并成为核心工具集的专家。单元测试工具需要通过某种模拟框架进行补充,并且都需要成为自动构建系统的一部分。您还希望选择并生成适当的指标。

你失去了个人自由,因为:

  • TDD是一种非常规范的编写代码的方式,它往往会与技能规模的顶部和底部的代码进行对比。始终以某种方式编写生产代码并使您的工作不断进行同行评审可能会让您的最差和最好的开发人员感到不安,甚至会导致员工流失。
  • 嵌入TDD的大多数敏捷方法都要求您不断地与客户讨论您打算完成的事情(在这个故事/日/其他事情中)以及权衡取舍。再一次,这不是每个人的一杯茶,无论是在围栏的开发者方面还是客户。

希望这可以帮助

24
Garth Gilmour

在编写代码以通过这些测试之前,TDD要求您规划类的操作方式。这是加号和减号。

我发现很难在“真空”中编写测试 - 在编写任何代码之前。根据我的经验,每当我在编写我的初级测试时忘记编写课程时不可避免地想到某些东西时,我倾向于绊倒我的测试。那么现在是时候不仅重构我的课程,而且还是我的测试。重复三到四次,这会令人沮丧。

我更喜欢先编写课程草稿,然后编写(并维护)一系列单元测试。我有一个草案后,TDD对我来说很好。例如,如果报告了错误,我将编写一个测试来利用该错误,然后修复代码以便测试通过。

14
Chrass

使用TDD进行原型设计可能非常困难 - 当您不确定要采取哪种解决方案时,预先编写测试可能很困难(除了非常广泛的测试之外)。这可能是一种痛苦。

老实说,我不认为绝大多数项目的“核心发展”都有任何真正的缺点;通常情况下,那些认为自己的代码足够好而且不需要测试的人(从来没有这样),而且那些平凡的人不会费心去编写它们。

12
Calum

好吧,这种拉伸,你需要调试你的测试。此外,编写测试还有一定的成本,尽管大多数人都认为这是一项前期投资,可以在节省时间的调试和稳定性方面为应用程序的生命周期带来回报。

不过,我个人最大的问题就是开始实际编写测试的规则。在一个团队中,特别是一个成熟的团队,很难说服他们花费的时间是值得的。

9
Tim Sullivan

TDD的缺点是它通常与“敏捷”方法紧密相关,这种方法对系统的文档放置 没有 重要,而不是为什么测试“应该”返回一个特定值而不是任何其他驻留的理解只在开发人员的头脑中。

一旦开发人员离开或忘记了测试返回一个特定值而不是其他一些值的原因,你就会被搞砸。 TDD很好,如果它有充分的文档,并且由人类可读(即尖头发的经理)文档包围,可以在世界变化和您的应用程序需要的5年内引用。

当我谈到文档时,这不是代码中的模糊,这是存在于应用程序外部的官方文字,例如管理人员,律师和必须更新的可怜的人员可以提及的用例和背景信息你的代码在2011年。

7
Ron McMahon

如果你的测试不是很彻底,你可能会因为测试通过而陷入“一切正常”的错误感觉。从理论上讲,如果您的测试通过,代码就可以了;但如果我们第一次不需要测试就可以完美地编写代码。这里的道德是确保在调用完整的东西之前自己做一个完整性检查,不要只依赖于测试。

在这方面,如果您的健全性检查发现未经测试的内容,请务必返回并为其编写测试。

7
Aaron Lee

我遇到过TDD让我发疯的几种情况。举几个:

  • 测试用例可维护性:

    如果您是一家大型企业,很多机会是您不必自己编写测试用例,或者至少大多数是在您进入公司时由其他人编写的。应用程序的功能会不时更改,如果您没有适当的系统(如HP Quality Center)来跟踪它们,您很快就会变得疯狂。

    这也意味着新团队成员需要花费大量时间来掌握测试用例的情况。反过来,这可以转化为更多的钱。

  • 测试自动化复杂性

    如果将部分或全部测试用例自动化为机器可运行的测试脚本,则必须确保这些测试脚本与其相应的手动测试用例同步并符合应用程序更改。

    此外,您将花时间调试可帮助您捕获错误的代码。在我看来,大多数这些错误来自测试团队未能反映自动化测试脚本中的应用程序更改。业务逻辑,GUI和其他内部资源的更改可能会使您的脚本停止运行或运行不可靠。有时,这些变化非常微妙,难以察觉。一旦我的所有脚本报告失败,因为它们基于表1中的信息计算,而表1现在是表2(因为有人在应用程序代码中交换了表对象的名称)。

6
Martin08

最大的问题是那些不知道如何编写适当的单元测试的人。他们编写的测试依赖于彼此(并且它们与Ant一起运行很好,但是当我从Eclipse运行它们时突然失败,只是因为它们以不同的顺序运行)。他们编写的测试不会特别测试任何东西 - 他们只是调试代码,检查结果,然后将其更改为test,称之为“test1”。它们扩展了类和方法的范围,只是因为为它们编写单元测试会更容易。单元测试的代码非常糟糕,所有经典的编程问题(重耦合,500行长的方法,硬编码值,代码重复)都是难以维护的。由于一些奇怪的原因,人们将单元测试视为低于“真实”代码的东西,并且他们根本不关心它们的质量。 :-(

5
rmaruszewski

你在编写测试时花了很多时间。当然,这可能会在项目结束时通过更快地捕获错误来保存。

4
Joel Coehoorn

在测试所有代码之前,你失去了说“完成”的能力。

在运行之前,您将失去编写数百或数千行代码的能力。

你失去了通过调试学习的机会。

您无法灵活地发布您不确定的代码。

你失去了紧密结合模块的自由。

您将失去跳过编写低级设计文档的选项。

你失去了每个人都害怕改变的代码所带来的稳定性。

你失去了“黑客”的称号。

4
Uncle Bob

最大的缺点是,如果你真的想要正确地做TDD,你必须在成功之前失败很多。鉴于有多少软件公司工作(每个KLOC美元),你最终会被解雇。即使您的代码更快,更清洁,更易于维护,并且具有更少的错误。

如果您在一家由KLOC向您付款的公司(或实施的要求 - 即使未经过测试)远离TDD(或代码审查,或结对编程,或持续集成等等)。

3
Vasco Duarte

重新关注困难的,无法预料的要求是程序员的不断祸根。测试驱动的开发迫使您专注于已知的世俗要求,并将您的开发限制在已经想象的范围内。

考虑一下,你很可能最终设计出特定的测试用例,所以你不会有创意并开始思考“如果用户可以做X,Y和Z那就太酷了”。因此,当该用户开始对潜在的冷却要求X,Y和Z感到兴奋时,您的设计可能过于拘泥于已经指定的测试用例,并且难以调整。

当然,这是一把双刃剑。如果您将所有时间都花在设计用户可能想要的每个可想象的,可想象的X,Y和Z上,那么您将不可避免地完成任何事情。如果你确实完成了某些事情,任何人(包括你自己)都不可能知道你在你的代码/设计中做了什么。

2
Doug T.

关于初始开发时间我的第二个答案。如果没有测试的安全性,你也会失去舒适的工作能力。我也被描述为TDD坚果吧,所以你可能会失去一些朋友;)

2
Chris Canal

它的速度越来越慢。从长远来看,这将不会让你感到悲伤,但是你最终会编写更多的代码,所以你可能会把时间花在“测试不编码”上。这是一个有缺陷的论点,但你确实问过!

1
MarcE

编写“随机”数据(如XML-feeds和数据库)(这并不难)编写测试可能既费时又费时。我最近花了一些时间处理天气数据源。为此编写测试令人困惑,至少因为我没有太多的TDD经验。

1
Vargen

进入它并花一些时间在一个项目中开始这样做但是...当我发现自动测试可能发现非常快的愚蠢错误时,我总是后悔没有做一个测试驱动的方法。此外,TDD提高了代码质量。

1
aerlijman

好的答案。我想补充一些方法来避免TDD的黑暗面:

  • 我写过应用程序来进行自己的随机自检。编写特定测试的问题是,即使你写了很多它们,它们只涵盖你想到的案例。随机测试生成器发现您没有想到的问题。

  • 大量单元测试的整个概念意味着您有可能进入无效状态的组件,如复杂的数据结构。如果您远离复杂的数据结构,那么测试就会少得多。

  • 在您的应用程序允许的范围内,不要依赖于通知,事件和副作用的正确排序的设计。那些很容易掉线或乱码,所以他们需要大量的测试。

1
Mike Dunlavey
  • 单元测试是更多的代码编写,因此更高的前期开发成本
  • 它需要维护更多代码
  • 需要额外学习
1
Bob Dizzle

您将失去承担多重责任的大班。您也可能会丢失具有多重职责的大型方法。你可能会失去一些重构能力,但你也会失去一些重构的能力。

杰森科恩说:TDD需要某个组织来代码。这可能在架构上是错误的;例如,由于私有方法不能在类外部调用,因此必须使非私有方法使其可测试。

我说这表明错过了抽象 - 如果私有代码确实需要测试,它可能应该在一个单独的类中。

戴夫曼

1
Dave Mann

您必须以不同的方式编写应用程序:一个使它们可测试的应用程序。你会惊讶地发现这有多么困难。

有些人在他们写得太难之前就找到了思考他们要写什么的概念。诸如模拟之类的概念对某些人来说也很困难。遗留应用程序中的TDD如果不是为测试设计的话可能会非常困难。围绕非TDD友好框架的TDD也可能是一场斗争。

TDD是一项技能,所以初级开发人员可能最初会挣扎(主要是因为他们没有被教导以这种方式工作)。

总的来说,虽然随着人们的熟练程度而得到解决,你最终会抽出“臭”的代码并拥有一个更稳定的系统。

1
Peter Gillard-Moss

教我的团队敏捷开发的人不相信计划,你只写了最小的要求。

他的座右铭是重构,重构,重构。我开始明白,重构意味着“没有提前计划”。

0
Jack B Nimble

让我补充一点,如果你将BDD原则应用于TDD项目,你可以减轻这里列出的一些主要缺点(混乱,误解等)。如果你不熟悉BDD,你应该阅读Dan North的介绍。他提出了这个概念,以回答在工作场所应用TDD引起的一些问题。可以找到Dan的BDD简介 这里

我只提出这个建议,因为BDD解决了其中一些负面问题,并充当了间隙停止。收集您的反馈意见时,您需要考虑这一点。

0
Kilhoffer

TDD需要某个组织来代码。这可能效率低或难以阅读。甚至在建筑上也是错误的;例如,由于private方法不能在类外调用,因此必须使方法非私有才能使它们可测试,这是错误的。

代码更改时,您还必须更改测试。通过重构,这可能是一项额外的工作。

0
Jason Cohen

您必须确保您的测试始终是最新的,当您开始忽略红灯时,测试变得毫无意义。

你还必须确保测试是全面的,或者在出现大错误的那一刻,你最终确信让你花时间编写更多代码的闷热管理类型会抱怨。

0
qui