添加单元测试对知名的旧版代码有意义吗?


21
  • 我说的是TDD意义上的单元测试。(不是自动的“集成”,或者您喜欢称之为测试的东西。)
  • 遗留代码,如:(C ++)没有测试的代码。(请参阅:Michael Feathers的“ 旧版代码有效工作”
  • 但是还有一些遗留代码,例如:我们的团队在过去10到5年中一直在使用的代码,因此我们通常对将事物放置在何处可以改变事物有一个很好的认识。
  • 我们确实某些模块进行单元测试(通过Boost.Test),这些模块后来出现或很自然地适合单元测试(常见的应用程序特定容器,字符串填充,网络助手等)。
  • 我们尚未进行适当的自动化验收测试。

现在,最近,我很高兴地实现了3个新的面向用户的功能。

每个人花了我大约1-2个小时来快速掌握我需要更改的代码部分,花了1-2小时来实现我需要更改的(小)代码,另外花了1-2个小时来确保应用程序之后正确运行,并且确实应该这样做。

现在,我确实添加了很少的代码。(我认为每个功能都有一个方法和一些调用行。)

分解出这段代码(通过WEwLC中建议的任何一种方法),以使单元测试变得有意义(而不是完整的重言式)将很容易又花费2-4个小时,甚至更多。这将为每个功能增加50%-100%的时间,而没有立即的好处,因为

  1. 我不需要单元测试即可了解有关代码的任何信息
  2. 手动测试的工作量是相同的,因为我仍然需要测试代码是否正确集成到应用程序的其余部分中。

当然,如果,以后,“有人”走过来,碰到的代码,他理论上可以有从单元测试的一些好处。(仅从理论上讲,因为经过测试的代码孤岛将生活在未经测试的代码海洋中。)

因此,“这一次”,我选择不做添加单元测试的艰苦工作:对代码进行更改以使要测试的东西要比对代码进行更改(要正确(清晰地)实现功能复杂得多

这是强耦合旧代码的典型代表吗?我是不是很懒?我们是否将团队的优先顺序设置错了?还是我谨慎,只测试开销不太高的东西?


如果其他部门将接管您的“众所周知的旧代码”怎么办?那里的家伙会做什么?
Alex Theodoridis

Answers:


18

您必须对这些情况保持务实。一切都必须具有业务价值,但是业务必须信任您才能判断技术工作的价值。是的,进行单元测试总是有好处的,但是这种好处是否足以证明花费的时间呢?

总是会在新代码上争论不休,但是在遗留代码上,您必须做出判断。

您经常在此代码领域吗?然后有一个持续改进的理由。您要进行重大更改吗?然后可能是已经是新代码的情况。但是,如果您要在一个复杂的区域中编写单行代码,而这一区域可能一年都不会被再次使用,那么重新设计的成本(更不用说风险)当然太高了。只需在那儿拍一行代码,然后快速洗个澡即可。

经验法则:始终对自己进行思考:“ 我认为,我认为我应该做的事比我要求做的工作要多得多,因此我认为我应该从这项技术工作中受益更多?


什么是好的代码?一种设计合理,经过测试,有据可查并具有未来证明的产品,还是一种您可以得到付款的产品?与往常一样:你可以把它很好的 ; 你可以便宜买到 ; 你可以快速拥有它。选择任何两个,第三个是您的费用。
Sardathrion-恢复莫妮卡2011年

2
“我总是会争论新代码”……旧代码库中的“新代码”还是“新代码”?:-)
Martin Ba

pdr有正确的想法。这是一项工程决策(需要权衡)。通常,如果您有大量经过审查的代码,则最好不进行处理。我已经看到TDD在遗留代码上的工作(仅一年,但这足够了)最终花费了几个月的时间,而最终却花费了很多钱并破坏了一个遗留应用程序几个月,直到TDD重构引入的错误得以修复。如果代码/功能已完成并经过测试,请不要破坏它以添加工具(TDD)以告诉您无论如何您已经知道的东西(它可以工作)。
匿名

10

从TDD的角度讲,单元测试的好处是获得独立的东西,而无需一支稳定的团队多年来建立的口头传统。

幸运的是,相同的团队已经在同一个项目上进行了很多次了。但这最终将改变。人们生病,无聊或晋升。他们移动,退休或死亡。新的思想带有新的思想,并渴望按照学校学习的方式重构一切。公司被买卖。管理政策改变。

如果您希望项目生存下来,则必须为更改做准备。


3

编写单元测试可以将来验证您的代码。 如果代码库中没有测试,则应该为所有新功能添加新测试,因为这会使代码的一部分变得更健壮。

我发现,即使在旧版代码中添加测试,从中长期来看也是有益的。如果您的公司不关心中长期,我会寻找另一家公司。另外,我认为手动测试不需要花费比编写集合单元测试更长的时间。如果是这样,那么您需要练习专注于编写测试的代码。


1
但是,但是,但是!:-)几乎不应该转化为实施新功能所需的时间增加100%。它并没有降低来实现后续功能所需的时间。它可以减少更换物品时所需的时间。
马丁·巴

3
您要确保在代码区域中所做的更改不会引入新的错误,新用户(经验不足的用户)可以清楚地了解代码,并且影响该区域的副作用在测试时(而不是发行时)会引起咳嗽。时间。测试有助于验证代码执行了应做的事情,从而使以后添加功能变得更加容易。我发现,即使从旧代码中添加测试,从中到长期都是有益的。如果您的公司不关心中长期,我会寻找另一家公司。
Sardathrion-恢复莫妮卡2011年

1
@Martin,因为显然您要做的是编写您认为该功能应具有的功能,然后发布它。在任何阶段都不会进行任何测试...不,请耐心等待。作为开发人员,我们都说完了(至少要手工测试)我们的代码。用“通过编写自动测试”代替“手工”并不是时间增加了100%。通常,我发现这大约是同一时间。
哈兹巨龙

1
@Kaz-“用“通过编写自动测试”替换“手工”并不是时间增加了100%。通常,我发现这大约花费了相同的时间。” -YMMV,但是对于我的代码库,这显然是错误的(如问题所示)。
马丁·巴

3
@Kaz: :-)的意思是:单元测试是隔离测试我的代码的。如果我不编写单元测试,则不会隔离测试代码,只有在正确调用代码并在应用程序中产生所需结果的情况下,才进行测试。无论如何(手动),我必须测试这两点(正确地和应做的事情应该做的),并且单元测试未涵盖这两个点。单元测试不会涵盖这两点,而会“孤立地”测试我的功能。(而且这个单元测试测试将是附加的,并且据我所知不会被任何东西抵消。)
Martin Ba

2

当然,最佳实践表明您应该对更改的任何代码进行单元测试。然而,现实世界的编码涉及许多折衷,时间和材料是有限的。

您需要做的是,在不进行单元测试的情况下,按实际价值评估错误修复和修改成本。然后,您可以评估创建这些测试的投资。单元测试大大降低了未来工作的成本,但现在付出了代价。

最重要的是,如果您的系统很少更改,则可能不值得编写单元测试,但是如果需要定期进行更改,则值得。


1

所有这些不进行测试的理性决定都在累积着严重的技术债务,一旦有人离职并且必须聘请新员工并加快工作速度,这些债务就会再次困扰您。

是的,编写单元测试可能还需要花费2-3个小时的时间,但是如果代码从测试中退回,您将不得不再次手动测试所有内容,并再次记录测试-您不是吗?否则,没人会知道您测试了什么以及使用了什么值?

单元测试记录了代码的预期行为以及用于检查功能的测试数据,并使新编码人员有足够的信心确保他们在进行更改时未破坏某些内容。

与人工测试相比,今天的测试要花费几个小时,但是您每次进行任何更改都需要进行测试,从而节省了代码寿命。

但是,如果您知道该代码将在几年后退役,那么我已经说过所有更改,因为您将无法完成对代码的测试,并且永远都无法收回。


“然后再次记录您的测试-是吗?” -{戴上愤世嫉俗的帽子:}当然不行。我们不在开发者仙境中。东西得到实施,测试和发货。后来,它被损坏,固定,测试并发货。
马丁·巴

我希望无论单元测试有多少,都可以手动测试所有内容。自动化的验收测试完全是另一回事。但是,由于传统的代码库并没有使验收测试变得更加困难,因此不在本文范围之内。
pdr

2
mcottle -你缺少一个关键点。单元测试不会减少完成功能的“手动功能测试”所花费的时间。我仍然必须单击所有与可能的输入的审慎子集有关的对话框,以确保所构建的实际完成的应用程序能够执行预期的操作。(我同意,如果单元测试确保仅在手动测试期间不会发现任何明显的问题,理论上单元测试可以将这个手动测试周期限制为一个循环。)
Martin Ba

0

单元测试的价值不仅在于开发新功能时对其进行测试。单元测试的好处大部分是在将来获得的。

是的,您可能需要花费看起来过多的时间才能使旧代码可测试。

但是,如果不这样做,您将或者肯定应该花费很多很多小时来测试该功能。不仅是最初的开发,还包括软件的每个新版本。没有单元测试和其他形式的自动化测试,您将没有其他选择,而是要花费大量时间进行手动测试,以确保即使不更改功能本身,也不会无意中破坏您的功能。


1
“没有单元测试,就没有任何其他手段可以确保您的功能不会被无意间破坏,即使该功能本身没有被更改也是如此。” -单元测试无济于事。为了确保这一点,我必须进行自动化的集成/验收测试。
马丁·巴

是的,单元测试只是第一步。编辑答案以弄清楚
Marjan Venema
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.