显然,某些旧应用程序不能或非常难以进行单元测试,因为它是最初编写的方式。
但是在某些地方,例如一些可能经过单元测试的辅助方法,我是否应该为它们编写单元测试呢?
我的意思是,它们可以像狗一样书写,但是无论逻辑多么脆弱,时间的考验都证明了它可以按预期的方式工作。如果我说要进行重构,我应该只打扰单元测试吗?还是应该在有空的时候为它们编写单元测试?
这样做有什么价值吗?
还应考虑到方法定义可能含糊不清,我可能需要研究在给定条件下某些方法应实际执行的操作。
显然,某些旧应用程序不能或非常难以进行单元测试,因为它是最初编写的方式。
但是在某些地方,例如一些可能经过单元测试的辅助方法,我是否应该为它们编写单元测试呢?
我的意思是,它们可以像狗一样书写,但是无论逻辑多么脆弱,时间的考验都证明了它可以按预期的方式工作。如果我说要进行重构,我应该只打扰单元测试吗?还是应该在有空的时候为它们编写单元测试?
这样做有什么价值吗?
还应考虑到方法定义可能含糊不清,我可能需要研究在给定条件下某些方法应实际执行的操作。
Answers:
我认为您当然应该为应用程序编写尽可能多的测试。他们将帮助您学习代码库,并为最终的重构或新开发做准备。
在这种情况下,您可以编写几种测试,每种测试都有自己的优点。编写这些测试将使您对正在处理的应用程序有很多了解。
首先,在开始编写测试的正确性之前,请编写捕获当前行为的测试,无论是对还是错。可以肯定地说,您将发现在极端情况下或在未经运行该程序彻底测试的代码部分中的错误。不必担心代码应该做什么,只需捕获它的工作即可。在继续过程中,不必担心阅读代码或花费大量时间弄清楚输出应该是什么。只需运行测试并在断言中捕获该输出即可。
这将使您对代码的操作方式以及主要的痛点或薄弱环节可能在哪里有一个坚实的了解。如果确实发现了错误,则可以与有能力的人联系,以决定他们是否值得修复,并做出这些决定。
接下来,您可以编写一些更大的(范围内)测试,这些测试涵盖了可能不容易进行单元测试的代码部分,但是在其中尽可能多地测试工作流仍然很重要。这些工作流程测试或集成测试(取决于您如何看待它们)将为您重构这些工作流程提供良好的基础,以使其更具可测试性,并在需要添加可能影响现有工作流程的新功能时为您提供保护。
随着时间的流逝,您将建立一整套测试,以帮助您或最终继承该应用程序的下一个人。
> Is there any value in writing unit tests for code that
> already works when inheriting applications?
NO。根据我的经验,在编写生产代码后编写单元测试会存在成本/收益关系不良,因为很难找到/很难在没有大量重构的情况下独立测试代码的方法。测试驱动开发的好处之一是您可以获得松散耦合的代码。如果您随后编写测试,则代码紧密耦合的可能性很高。
是的,您可以为计划进行更改的功能的应用程序编写集成测试。这样,您可以进行回归测试以查看您的更改是否破坏了某些内容。
YES但从质量和开发商一点上是有测试的价值。
NO从企业角度来看,因为它是很难卖给顾客,你需要时间/钱没有得到真正的商业价值,但含糊的承诺,企业的变化不会使事情变得更糟。
如果有可能,甚至还有更多的理由为“已经起作用”的现有代码编写测试。如果没有测试,那么代码很可能带有气味,可以使用大量的重构进行改进。测试套件将帮助您进行重构。它甚至可能表明原始代码无法正常工作。我回想起我曾经写过一种测试方法来生成销售报告的方法,但发现计算方法不正确,因此销售额比实际值高了几千美元,而且五年来没人知道代码在生产中(幸运的是,这并不是实际的财务目标,只是销售报告的估算值)。
当然,仅当您实际上可以编写测试时,此建议才适用。以我的经验,没有测试的代码库几乎不可能改装测试,因为您将不得不重写一半的代码模块,使其足够抽象以首先支持测试,而您将无法做到这一点。
绝对可以,因为单元测试不应验证正确性,而应描述系统的实际行为。特别是对于遗留项目,许多要求都隐式编码在实际行为中。
此特征用作功能的基准。即使从业务的角度来看行为不正确,您也可以避免行为进一步恶化。在旧项目中获得牵引力可能很困难,这为您提供了基线,以便您可以继续前进而不会使情况变得更糟。
因此,编写所有可以的单元测试。对于无法测试的代码,可以通过在代码中引入“接缝”来重构代码以分离依赖关系,在这些位置可以将要测试的代码与不需要测试的代码分开。
我强烈推荐的一本书,迈克尔·费瑟斯(Michael Feathers)提出的将单元测试作为特征测试和接缝的思想是要有效地使用遗留代码的重点。
不要仅仅因为应用程序已启动并正在运行就假设一切正常……通常,“时间考验”仅表明a)您还没有发现其余的缺陷,或者b)找到的人他们还没有举报。(或者也许两者兼有。)即使是现在可能正在工作的代码,在下次必须进行更改时也可能无法工作。
单元测试使您可以确定某些功能是否完好无损,同时还为您提供了一种在合理数量的情况下对此进行演示的方法。这比“仔细研究并测试”更有价值,即使是针对单个错误的修复。(四处走动更像是集成或系统测试,因此从这个意义上讲,手动测试应用程序可以覆盖的单元测试远远超过单独的单元测试,但这仍然是效率低下的时间。甚至是一些自动化这些测试的方法也是比手动操作要好。)
无论更改是固定的还是重构的,您绝对应该在更改代码时编写测试。您可能会做得很好,可以编写测试,如果没有其他原因,除了在下次必须修复某个缺陷(并且下次还会修复)上节省一些时间的时候……尽管在这种情况下,您会必须在假装软件始终无缺陷的人的期望与期望之间取得平衡,从而“浪费”了用于未来维护的时间。(不过,这并不意味着您应该忽略当前的计划。)在某个时候,如果您这样做,您将具有足够的覆盖范围,可以开始证明对旧版应用程序进行测试的价值,这可能有助于您花费在将来的应用程序上花时间,最终应该腾出时间来进行生产性开发。