将单元测试添加到遗留代码

Buc*_*Guy 77 unit-testing legacy-code

事实上,您是否曾将旧单元测试添加到遗留代码中?代码有多复杂,存根和模拟一切有多难?最终结果值得吗?

Jam*_*ack 56

我发现,最好的方法是逐步添加单元测试,而不仅仅是跳入并说我们现在将对应用程序进行单元测试.

因此,如果您要触摸代码,修复错误或重构,那么首先编写单元测试.对于错误,单元测试将有助于证明问题所在,因为您可以复制它.

如果重构,您将需要编写单元测试,但您可能会发现测试无法编写,因此您可能需要找到一个高级别,调用将被重构的函数,并对该部分进行单元测试.然后,在重构攻击性函数时,编写测试以确保它按预期运行.

没有简单的方法可以做到这一点.

这个问题可能有助于提出更多建议. 如何将单元测试引入大型遗留(C/C++)代码库?

  • +1用于逐步添加测试. (8认同)

Phi*_*gan 39

Michael Feathers的书"有效地使用遗留代码"是一本涵盖这一主题的完整书籍.迈克尔表示,为遗留代码引入测试通常太困难,因为它的结构不可测试.我从书中得到的最多的是一些名为"Sprout functions"和"Sprout classes"的模式.sprout函数是封装您需要在代码中进行的更改的函数.然后,您只能单独测试这些功能.除了新功能包含在类中之外,sprout类是相同的想法.


Tru*_*ill 9

是的,这通常是痛苦的.我经常最终不得不编写集成测试.

" 单元测试的艺术 "一书对此有一些很好的建议.它还建议使用" 有效使用遗留守则 "一书; 我还没有读过后者,但它在我的堆栈上.

编辑:但是,即使是最小的代码覆盖也是值得的.它给了我重建代码的信心和安全网.

编辑:我确实读过有效的遗留代码工作,它非常好.

  • "有效使用遗产代码"的+1:充满了很好的建议; 实际上,即使对于绿地环境,它也非常值得阅读,就像构建可测试性代码的一个很好的资源一样. (3认同)

zav*_*avg 6

另请参阅遗留代码单元测试领域的新方法--Asis项目,它受到ApprovalTests项目的启发并分享其关键概念.

如前所述约在ApprovalTests办法这篇文章:

通常,您有一个巨大的遗留代码项目,您根本没有测试,但您必须更改代码以实现新功能或重构.遗留代码的有趣之处在于 - 它有效!它可以工作多年,无论它是如何编写的.这是该代码的一个非常大的优势.通过批准,只有一个测试,您可以获得所有可能的输出(HTML,XML,JSON,SQL或它可能的任何输出)并批准,因为您知道 - 它的工作原理!在完成这样的测试并批准结果后,通过重构,您实际上更加安全,因为现在您"锁定"了所有现有行为.

Asis工具正是通过自动创建和运行特征测试来保留遗留代码.

有关详细信息,请查看


And*_*are 5

如果您计划重构遗留代码,那么必须创建这些单元测试。不要担心模拟或存根 - 担心测试系统的输入和输出,以便您的更改或重构工作不会破坏当前功能。

我不会对你撒谎,对遗留代码进行单元测试改造很困难——但这是值得的。


phi*_*ant 5

单元测试的一种替代方案,也在有效地使用遗留代码中引入,是特征测试.这些测试我得到了有趣的结果.当您从点测试时(比称为接缝),它们比单元测试更容易设置.缺点是当测试失败时,您对问题的位置的暗示较少,因为测试区域可能比单元测试大得多.记录有助于此.


像xUnit系列那样的单元测试框架可用于编写特征测试.

在这样的测试中,在事实之后编写,断言验证了代码的当前行为.与单元测试不同,它们不能证明代码是正确的,它们只是固定(表征)代码的当前行为.

该过程与TDD类似:

  • 为一部分代码编写测试
  • 执行它 - 失败
  • 从观察到的代码行为中修复测试
  • 执行它 - 通过
  • 重复

如果修改代码的外部行为,测试将失败.代码的外部行为?听起来很熟悉 ?是的,我们在这里.现在你可以重构代码了.

显然,风险取决于特征测试的覆盖范围.


Lyn*_*git 5

看一下免费的开源单元测试实用程序库ApprovalTests.如果您是.NET开发人员,创建者Llewellyn Falco已经制作了一系列视频,展示了他如何使用ApprovalTests来改进新旧代码的单元测试.