为继承应用程序的代码编写单元测试是否有任何价值?


27

显然,某些旧应用程序不能或非常难以进行单元测试,因为它是最初编写的方式。

但是在某些地方,例如一些可能经过单元测试的辅助方法,我是否应该为它们编写单元测试呢?

我的意思是,它们可以像狗一样书写,但是无论逻辑多么脆弱,时间的考验都证明了它可以按预期的方式工作。如果我说要进行重构,我应该只打扰单元测试吗?还是应该在有空的时候为它们编写单元测试?

这样做有什么价值吗?

还应考虑到方法定义可能含糊不清,我可能需要研究在给定条件下某些方法应实际执行的操作。


4
请帮个忙,并阅读“有效使用旧版代码”。如果是一整本书,专门回答这个问题和其他相关问题。
Rein Henrichs

Answers:


15

我认为您当然应该为应用程序编写尽可能多的测试。他们将帮助您学习代码库,并为最终的重构或新开发做准备。

在这种情况下,您可以编写几种测试,每种测试都有自己的优点。编写这些测试将使您对正在处理的应用程序有很多了解。

首先,在开始编写测试的正确性之前,请编写捕获当前行为的测试,无论是对还是错。可以肯定地说,您将发现在极端情况下或在未经运行该程序彻底测试的代码部分中的错误。不必担心代码应该做什么,只需捕获它的工作即可。在继续过程中,不必担心阅读代码或花费大量时间弄清楚输出应该是什么。只需运行测试并在断言中捕获该输出即可。

这将使您对代码的操作方式以及主要的痛点或薄弱环节可能在哪里有一个坚实的了解。如果确实发现了错误,则可以与有能力的人联系,以决定他们是否值得修复,并做出这些决定。

接下来,您可以编写一些更大的(范围内)测试,这些测试涵盖了可能不容易进行单元测试的代码部分,但是在其中尽可能多地测试工作流仍然很重要。这些工作流程测试集成测试(取决于您如何看待它们)将为您重构这些工作流程提供良好的基础,以使其更具可测试性,并在需要添加可能影响现有工作流程的新功能时为您提供保护。

随着时间的流逝,您将建立一整套测试,以帮助您或最终继承该应用程序的下一个人。


13

我将单元测试视为规范,而不仅仅是测试。在特定情况下,您已经提到,在进行任何更改以符合新规格之前进行适当的单元测试时,真正的价值就会显现。如果您要更改继承的代码,那么我认为最好的方法是对功能进行单元测试,这不仅会带来安全网,而且还可以帮助我们更清楚地了解特定单元的功能。它也可能迫使您进行一些您提到的研究,这对理解很有帮助。因此,我的想法是在即将进行更改之前,对模块的单元测试进行准备。


用可以使用的最高级语言编写测试。当要求您估计进行更改的时间时,请包括编写缺少的测试所需的时间。您可能需要花费更长的时间进行更改,但是您将在该字段中放置更少的错误。
凯文·克莱恩

8
 > Is there any value in writing unit tests for code that 
 > already works when inheriting applications?

NO。根据我的经验,在编写生产代码后编写单元测试会存在成本/收益关系不良,因为很难找到/很难没有大量重构的情况下独立测试代码的方法。测试驱动开发的好处之一是您可以获得松散耦合的代码。如果您随后编写测试,则代码紧密耦合的可能性很高。

是的,您可以为计划进行更改的功能的应用程序编写集成测试。这样,您可以进行回归测试以查看您的更改是否破坏了某些内容。

YES但从质量和开发商一点上是有测试的价值。

NO从企业角度来看,因为它是很难卖给顾客,你需要时间/钱没有得到真正的商业价值,但含糊的承诺,企业的变化不会使事情变得更糟。


对于这种情况,+ 1用于集成测试而不是单元测试。非常务实的建议
gbjbaanb

5

如果有可能,甚至还有更多的理由为“已经起作用”的现有代码编写测试。如果没有测试,那么代码很可能带有气味,可以使用大量的重构进行改进。测试套件将帮助您进行重构。它甚至可能表明原始代码无法正常工作。我回想起我曾经写过一种测试方法来生成销售报告的方法,但发现计算方法不正确,因此销售额比实际值高了几千美元,而且五年来没人知道代码在生产中(幸运的是,这并不是实际的财务目标,只是销售报告的估算值)。

当然,仅当您实际上可以编写测试时,此建议才适用。以我的经验,没有测试的代码库几乎不可能改装测试,因为您将不得不重写一半的代码模块,使其足够抽象以首先支持测试,而您将无法做到这一点。


为什么要对事实表白呢?
韦恩·莫利纳

4

绝对可以,因为单元测试不应验证正确性,而应描述系统的实际行为。特别是对于遗留项目,许多要求都隐式编码在实际行为中。

此特征用作功能的基准。即使从业务的角度来看行为不正确,您也可以避免行为进一步恶化。在旧项目中获得牵引力可能很困难,这为您提供了基线,以便您可以继续前进而不会使情况变得更糟。

因此,编写所有可以的单元测试。对于无法测试的代码,可以通过在代码中引入“接缝”来重构代码以分离依赖关系,在这些位置可以将要测试的代码与不需要测试的代码分开。

我强烈推荐的一本书,迈克尔·费瑟斯(Michael Feathers)提出的将单元测试作为特征测试和接缝的思想是要有效地使用遗留代码的重点。


2

我自己考虑过这一点,因为在我们的系统中有很多未编写文档的接缝写得很差,但是可以正常工作。

您提出了一个很好的观点:

如果我说要进行重构,我应该只打扰单元测试吗?还是应该在有空的时候为它们编写单元测试?

如果需求发生变化,我认为编写单元测试将是最有价值的。如果没有,我不会特别打扰,因为您将无法编写适当的测试,因为您不知道所有条件。

每当我有时间吗?

您有时间优先考虑它,对吗?所以它永远不会发生。:)


1

您是否要利用该代码库中以前未在生产应用程序中使用过的方面?首先为这些方案编写单元测试。您需要能够在这里确定工作的优先级,我认为单元测试的艺术在这方面提供了一些建议(尤其是如何进行遗留代码库的测试)。


1

不要仅仅因为应用程序已启动并正在运行就假设一切正常……通常,“时间考验”仅表明a)您还没有发现其余的缺陷,或者b)找到的人他们还没有举报。(或者也许两者兼有。)即使是现在可能正在工作的代码,在下次必须进行更改时也可能无法工作。

单元测试使您可以确定某些功能是否完好无损,同时还为您提供了一种在合理数量的情况下对此进行演示的方法。这比“仔细研究并测试”更有价值,即使是针对单个错误的修复。(四处走动更像是集成或系统测试,因此从这个意义上讲,手动测试应用程序可以覆盖的单元测试远远超过单独的单元测试,但这仍然是效率低下的时间。甚至是一些自动化这些测试的方法也是比手动操作要好。)

无论更改是固定的还是重构的,您绝对应该在更改代码时编写测试。您可能会做得很好,可以编写测试,如果没有其他原因,除了在下次必须修复某个缺陷(并且下次还会修复)上节省一些时间的时候……尽管在这种情况下,您会必须在假装软件始终无缺陷的人的期望与期望之间取得平衡,从而“浪费”了用于未来维护的时间。(不过,这并不意味着您应该忽略当前的计划。)在某个时候,如果您这样做,您将具有足够的覆盖范围,可以开始证明对旧版应用程序进行测试的价值,这可能有助于您花费在将来的应用程序上花时间,最终应该腾出时间来进行生产性开发。


0

从我的乐土出发,我不仅会说是,而且会破解,重构并继续进行测试,但要确保您在其他重要项目中不会落后。 作为一名正在工作的程序员,如果您的工作有风险,或者如果经理告诉您拥有所有权,那么可以。如果团队或公司可能遭受损失,请与您的经理协商,让他知道进行测试以防止公司遭受灾难的必要。如果他说不用担心,那您就没必要了(不一定是责备委派是一种管理技能,所以请确保您真的没错……真的!)

祝好运!

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.