单元测试或测试驱动的开发值得吗?


48

我的工作团队正在迁移到Scrum,其他团队也开始使用单元测试和用户接受测试来进行测试驱动的开发。我喜欢UAT,但是对于测试驱动的开发或通常测试驱动的开发,我不出售单元测试。

看来编写测试是一项额外的工作,使人们在编写实际代码时显得cr不休,而且可能并不经常有效。

我了解单元测试如何工作以及如何编写它们,但是任何人都可以证明这确实是一个好主意,值得付出时间和精力吗?

另外,还有什么使TDD特别适合Scrum的?


27
如果您想确保您的软件经常崩溃,或者几乎完全无法维护,并且应该在实际投入生产之前进行更换;那么我建议您完全放弃单元测试,不要花时间学习TDD。
达伍德·伊本·卡里姆

3
考虑一下重构的愿望/需求。当您无意间破坏了某些内容时,无论是否进行一套全面的单元测试,您是否会对在进行重构(无论何种规模)时更有信心?
Marjan Venema'3

2
“在编写真实代码时给人们一个拐杖”?不能以这种方式描述大多数最佳实践吗?
user16764 2012年

4
@DavidWallace:这是开发人员不称职的问题,而不是缺乏TDD。而且,即使TDD被广泛使用,它也提供了零保证,即您所做的更改不会破坏任何内容。
编码员2012年

6
@NimChimpsky:我对TDD没有负面看法,我只是不大肆宣传。它有积极的一面,也有消极的一面。错误的安全感就是其中之一。
编码员

Answers:


68

简短的回答:绝对肯定。

长答案:单元测试是我在工作场所(大型银行,外汇交易)尝试并影响的最重要实践之一。是的,它们是多余的工作,但这项工作会一次又一次地回报。自动化的单元测试不仅可以帮助您实际执行所编写的代码,当然还可以验证您的期望,而且还可以充当您或他人可能进行的将来更改的监视者。当有人以不希望的方式更改代码时,将导致测试失败。我认为单元测试的相对价值与代码库中预期变化的程度和增长程度之间的相关性下降,但是即使预期变化很小,对代码所做的事情的初步验证也值得。单元测试值还取决于缺陷的成本。如果缺陷的成本(成本是时间/金钱/声誉/未来工作的损失)为零,则测试的相对值也为零;但是,在商业环境中几乎从来没有这种情况。

我们通常不再雇用不再按常规创建单元测试作为工作一部分的人员-这只是我们所期望的,例如每天都在工作。我还没有看到过进行单元测试的纯粹的成本效益分析(有人可以指点我),但是我可以从经验中说,在商业环境中,能够证明代码在大型重要系统中有效是值得的。这也使我知道自己编写的代码可以正常工作(达到一定水平),使我在晚上睡得更好,并且如果更改了代码,则会因构建损坏而使人警觉到任何意外的副作用。

我认为测试驱动开发不是测试方法。它实际上是一种设计方法/实践,其输出是工作系统和一组单元测试。我不太相信这种做法,因为这项技能很难发展和完善。就我个人而言,如果我正在构建一个系统,但我对它的工作方式尚不明确,我将聘请TDD帮助我在黑暗中找到自己的出路。但是,如果我要应用现有的模式/解决方案,则通常不会。

在没有数学证明可以编写单元测试的情况下,我鼓励您长时间尝试并亲自体验所带来的好处。


5
我要补充的是,单元测试还使您考虑界面设计。当您进入“我如何对私有方法进行单元测试?”这一部分时,您就知道可能是您的界面有问题。
TC1 2012年

1
“我鼓励您长期尝试,并亲自体验所带来的好处。” 一次尝试就足够了,好处似乎显而易见。
NimChimpsky

1
为“我们通常不再雇用不再定期创建单元测试作为工作一部分的人员” +1。我最近不得不拒绝一个候选人,他在其他缺点中强烈宣称他不喜欢编写自动测试,因为它们浪费时间,而且他可以自己测试代码。
ftr 2012年

4
您不能仅仅通过使用自动化测试来证明非平凡的代码能以任何相关方式起作用。使用自动化测试,您只能证明代码可以通过测试 -如果测试覆盖了100%的用例,则可能具有“一定级别”,但这并不意味着代码“可以正常工作”。为了具有真正的可证明性,您需要en.wikipedia.org/wiki/Formal_verification-因此,此处使用的术语“可证明”是错误的。
vaxquis 2015年

1
@vaxquis是的,您对术语证明的使用完全正确。但是我敢打赌,测试的存在(或TDD的实践)比没有测试更好地证明了一个工作系统。
rupjones

16

较早发现的错误比较晚发现的错误的修复成本更低。TDD可帮助您验证系统的正确性。您预先投资了一些,但稍后再收回。该图有点夸张,但是很好地说明了这个想法。

在此处输入图片说明

图片来源


您所说的传统是什么?任何不是TDD的东西吗?
乔治

似乎该图不是基于某些真实的统计数据,它仅表示在2006年撰写此Blog条目的一个人的经历。不是说我完全错了,而是现实要复杂得多。
布朗

9

单元测试或测试驱动的开发值得吗?

是的,确实如此。鲍伯叔叔(罗伯特·C·马丁)在一次演讲中说。

对于开发人员来说,证明自己的代码比喊叫,唱歌或跳舞要好得多,从而可以更好地编写并通过测试

而且由于您不打算删除测试,因此只要测试通过,就可以确定功能正常 -回归问题已解决。

上面写了很多东西,

  1. 您有责任使该功能正常工作。编写测试。去做就对了。
  2. 何时用集成测试替换单元测试

SCRUM,单元测试和TDD相关吗?

很快,当您是一位大师时,Unit testing您将很近TDDSCRUM与之无关,但是正如他们所说,伟大的事情很好地融合在一起,如果您还没有尝试过的话,这些开发软件的技术就可以组合成一个出色的堆栈

有什么使TDD特别适合SCRUM的吗?

如我上面所说,它们很好地结合在一起 ; 如果在其中添加一些自动化测试,那么它会更加特殊


8

看来编写测试是一项额外的工作,使人们在编写实际代码时显得cr不休,而且可能并不经常有效。

单元测试作为拐杖具有价值。它支持您的开发工作,使您可以更改实现,而不必担心应用程序将按需停止工作。单元测试还不仅仅局限于拐杖,因为它们为您提供了一个工具,您可以使用该工具来验证您的实现是否符合要求。

所有测试,无论是单元测试,验收测试,集成测试等等,都仅与使用它们的人一样有效。如果您随便处理您的工作,那么您的测试将很草率,并且您的实现会遇到问题。那为什么要打扰呢?您费心测试,因为您需要向自己和您的客户证明您的软件可以运行,并且没有任何可能妨碍软件使用的问题。是的,测试绝对是额外的工作,但是测试的进行方式将确定发行后需要花费多少精力来修复错误,以及代码需要多少精力来更改和维护。

我了解单元测试如何工作以及如何编写它们,但是任何人都可以证明这确实是一个好主意,值得付出时间和精力吗?

TDD,实际上任何需要您在编写代码之前编写测试的方法都采用了您尽早尝试的方法,作为未来技术债务的预付款。在您进行项目工作时,任何遗漏或实施不当的事情都会以增加维护难度的形式招致更多的技术债务,这直接影响未来的成本和资源需求。预先进行测试可以确保您不仅努力解决未来的技术债务,而且还可以确保对您的需求进行编码,以便可以通过运行代码来对其进行验证。首先进行测试还可以让您有机会在致力于解决代码问题之前验证对问题域的理解,并验证您的实现工作。

这实际上归结为试图最大化代码的业务价值。一般而言,未经测试且难以维护的代码通常价格便宜,创建速度快,并且在产品发布后的整个生命周期内维护成本很高。通常,在单元级别上经过彻底测试的代码创建起来更昂贵,但是在发布后的整个产品生命周期中维护成本却相对较低。

另外,还有什么使TDD特别适合SCRUM的吗?

TDD不适用于任何特定方法。它只是一个工具。您可以将其集成到开发过程中以帮助您实现特定结果的一种做法。因此,为回答您的问题,TDD是对您的方法的补充,无论是SCRUM还是任何其他方法。


6

人们认为这是额外的努力,因为这是一项前期活动。您失去的时间现在会在以后恢复。

我进行单元测试的原因还包括:

给您一个目标:如果您不知道软件应该做什么,就不能编写测试。这有助于尽早消除规范中的问题。

给您进步感。

如果代码更改会更改其他代码区域的输出,则向您发出警告。这使得重构更加容易。

提供额外的文档层(尤其是如果您对测试进行正确注释时)。

鼓励各种良好做法。因为测试应该快速运行,所以它鼓励您编写解耦的代码并支持模拟。所有这些都有助于重构。

该主题的其他文章中也介绍了其他内容。这是值得的。


2

单元测试或测试驱动的开发值得吗?

绝对可以(请参阅其他答案)

[是]确实是个好主意,值得付出努力和时间吗?

  • 是的,如果您重新开始(添加新模块或全新的应用程序)
  • 否,如果已经有很多现有的代码不是由测试驱动开发的,必须进行扩展(传统)。

我认为,如果您在实际代码之前编写单元测试那么测试驱动的开发最有效。这样,满足测试要求的代码就变得清晰可见,并带有最少的易于测试的外部引用。

如果没有单元测试的代码就已经存在,那么以后编写单元测试通常会花费很多额外的工作,因为代码不是为便于测试而编写的。

如果您执行TDD,则自动测试代码很容易。


2

让我从另一侧着手解决这个问题。当您开发没有单元测试的简单应用程序时会发生什么?如果您有一个好的QA部门,那么首先发生的事情之一就是您会发现报告的问题很多。为什么要这样做,因为您没有测试所做的事情并认为它会起作用,又因为您没有过多关注要求而您的应用程序不满足要求。糟糕,回到绘图板上进行重写和修复。现在,您已经进行了修复,并发现了一系列全新的问题,因为在进行质量检查之前,您无法验证您的修复是否对其他任何问题都没有影响。糟糕的截止日期已经过去了,管理层也很沮丧。

如果您没有一个好的QA部门,情况会更糟,因为这样用户会发现错误,不仅会令老板不满意,还会使生产环境崩溃,数百人甚至数千人会陷入困境。修复单元测试可以避免的错误时停滞不前。这不是一个好的职业选择。

现在,假设这种牛仔方式持续了多年?现在,每一个变化,即使是微不足道的变化,似乎都冒出了一个新的未曾想到的问题。不仅如此,您还想做很多事情来使应用程序更好地工作,而您却无法做,因为它们风险太大,成本太高或两者兼而有之。因此,您在补丁程序上放置了补丁程序,使系统变得越来越复杂,而且bug越来越多,使用起来也更加困难。

用户开始质疑您的时间估算值,因为它们越来越大,很难向他们解释系统已经变得如此复杂,很难找到在哪里进行更改,更难于确定他们不会这样做。不要破坏其他东西。

我在这样一个地方工作了十年,经过十年的发展,实际上我们不想做任何解决实际问题的工作,因为我们无法确定数百个定制的客户端应用程序中哪个会损坏。最初的开发人员非常类似于“单元测试,我们不需要臭的单元测试”类型的开发人员。跟随他们的每个人都因目光短浅而受苦。

如果没有单元测试,则软件会很麻烦,并且最初开发和维护都需要更长的时间。你到底为什么不想做单元测试?您花费在编写测试上的时间将远远少于您花费在解决应早发现的问题上的时间(发现错误的时间越早,则花费在解决该问题上的时间就越少)以及通过编写测试就可以完全避免的问题首先,可以在开始编码之前更好地了解需求。


1

您编写的所有代码都需要在某个时候进行测试。您不想一次写完所有内容,然后按下编译按钮并用手指交叉。您可以编写和编译小块,并在代码中发送精心设计的输入,以验证其是否按照您的预期进行。然后,您通常会删除临时测试设备,然后继续进行下一个组件。

使用单元测试,它可以简化此过程,并为您提供进行测试的借口。这样,如果您进行的任何更改破坏了您过去测试过的内容,则可以显式捕获该回归,而不是让其影响代码的其他部分。有真正的价值。

至于TDD的红绿重构方法,我觉得有些乏味。但每一个他自己。


1
对于我的2c:为了知道您的测试是否确实有效,您需要在测试通过之前先查看它们是否失败。令人遗憾的是,我见证了许多开发人员编写的测试似乎正在运行,但是当测试条件发生变化时,即使测试应该失败,代码仍然可以通过测试。如果测试先失败然后再通过,那么您编写的测试很可能没有错误。如果您在代码更改后最终修改了测试,则不能确定代码是否正确。是的,这很乏味,但是正确的可能性更大。:-)
S.Robins 2012年

0

在大多数情况下,我发现开发人员对编写测试的想法有弹性。他们并不是说测试没有价值,而是说它们只是弄清楚如何解决特定问题的一种手段。通常,此问题根据上下文而变化。一旦完成,测试就无用了,也可以删除。这是我的同事过去给出的有关如何决定何时编写测试的上下文示例,您将发现根据它们得出的唯一可能答案是:

  • 问题一定是TDD的教科书示例,例如堆栈或计算器
  • 琐碎的代码不应该进行测试(使先前的参数无效)
  • 关键或困难的代码应进行彻底测试(由先前的参数暗示)
  • 测试不应与实现紧密耦合,以允许进行全面重构(使先前的参数无效)
  • 无需测试副作用,例如使用特定的有效负载调用第三方服务(因此无需进行黑盒测试)

实际上,我发现一种测试被普遍接受,我认为最终没有用。即基于GUI的测试,例如通过使用硒,webdriver,watir或arquillian。这就是我们在TDD项目中获得7小时构建周期而不是5分钟构建周期的方式。

这些相同的开发人员通常会与其他人一起抱怨代码的糟糕程度以及以前的开发人员必须具备的能力。他们还发现,使用白板,MS Office或Wiki进行正确的设计非常重要,并要格外小心以确保该设计保持最新状态。

最后一个让我真正意识到这些开发人员是欺诈。我们都知道,任何非单元测试的设计文档都会过时,并且由于维护成本高昂而无法及时更新。实际上,我已经尝试并试图提供一种以MS Office格式表达设计思想的好方法,这在编写代码之前和之后都非常有用且清晰易读。在所有情况下,我都失败了,尽管有些人设法制作了一份MS Office文档,看上去似乎很漂亮,但我从未真正找到那些有用的文档。

因此,您可以选择。您可以通过实践TDD来进行设计和文档编制,根据我10年的开发经验,TDD是生产此类文档的唯一已知且经过验证的方法。或者您可以进入政治。


1
测试不是文档。TDD是一个很好的实践,但是很多时候开发人员使用auto-gen工具吐出过于简化的测试存根。如果您有一个拒绝这样做的开发人员,请尝试编写更大的测试工具,以使用更多的整个产品,而不是编写细粒度的测试。他们会发现这显然有用。但是,您仍然必须编写适当的文档,这无可避免。
gbjbaanb 2012年

@gbjbaanb:如果开发人员使用自动生成工具,则可能正在编写单元测试,但绝对不是TDD。在TDD中,您应该在方法之前编写测试。您无法自动执行尚不存在的方法的测试脚手架。书面的测试也是很好文件(针对项目开发人员的技术文件,不需要用户手册)。编写良好且维护良好的单元测试向您展示了方法应如何进行测试。而且,如果定期检查并成功进行测试,显然比过时的文档更准确。你不能否认这一点。
克里斯,

单元测试可能是一个很好的开发人员文档,因为它们显示了如何使用api的示例。
2013年

硒,webdriver等的要点是,您不必手动对网站进行质量检查。因此,您不会通过从构建过程中删除它们来节省时间,因为它们本身就是为了节省时间。
Muhd
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.