在事后给旧代码添加单元测试,你有这样的经历吗?那时候代码有多复杂,每件事情都需要模拟和替身,这有多难?最终结果是否值得?
在事后给旧代码添加单元测试,你有这样的经历吗?那时候代码有多复杂,每件事情都需要模拟和替身,这有多难?最终结果是否值得?
迈克尔·菲瑟斯的书《与遗留代码高效工作》是一本完整介绍这个主题的书。迈克尔表示,为遗留代码引入测试通常很困难,因为它没有被设计为可测试的。我从这本书中最多得到了两个名为“萌芽函数”和“萌芽类”的模式。 萌芽函数是将您需要在代码中进行的更改封装起来的函数。然后,您仅对这些函数进行单元测试。而萌芽类是相同的想法,只是新功能包含在类中。
是的,而且通常很痛苦。我经常不得不编写集成测试。
这本书《单元测试之道》给出了一些好的建议。它还推荐了另一本书《与遗留代码高效工作》,我还没有读过后者,但它在我的书单上。
编辑:但是,即使仅有最少的代码覆盖率也是值得的。它给了我信心和重构代码的安全保障。
编辑:我确实读了《与遗留代码高效工作》,它非常好。
另外,还要看一下在遗留代码单元测试领域的新方法 - Asis项目,它受到了ApprovalTests项目的启发,并分享了其关键概念。
正如本文中提到的ApprovalTests方法:
Asis工具的主要目的是通过自动创建和运行特征测试来维护遗留代码。通常情况下,你有一个巨大的遗留代码项目,没有任何测试,但你必须更改代码以实现新功能或进行重构。关于遗留代码的有趣之处在于 - 它工作!它可以工作多年,无论它是如何编写的。这是该代码的一个非常大的优势。通过批准测试,只需一个测试即可获得所有可能的输出(HTML、XML、JSON、SQL或任何其他输出),并进行批准,因为您知道 - 它可以工作!完成此类测试并批准结果后,您进行重构时会更加安全,因为现在您已经“锁定”了所有现有行为。
工作有效地处理遗留代码中提到的一种替代单元测试的方法是特性测试。我通过这些测试获得了有趣的结果。与单元测试相比,设置起来更容易,因为你可以从可以被测试的点(称为接缝)进行测试。缺点是当测试失败时,你对问题位置的线索较少,因为被测试的区域可能比单元测试大得多。在这里,记录帮助解决问题。
可以使用像xUnit家族这样的单元测试框架来编写特征测试。
在这种测试中,断言验证代码的当前行为,这些测试是在事实之后编写的。与单元测试不同的是,它们不能证明代码是正确的,它们只是确定(描述)了代码的当前行为。
该过程类似于TDD:
如果修改代码的外部行为,则测试将失败。外部行为?听起来熟悉吗?是的,在这里我们就是。现在您可以重构代码。
显然,风险取决于特征测试的覆盖范围。
我之前曾经谈到过在XPDays http://xpdays.com.ua/archive/xp-days-ukraine-2012/materials/legacy-code/ 上关于反转测试金字塔在遗留代码中的想法。
这个演示应该回答了一个问题:为什么有时候在处理遗留代码时,从集成/功能甚至高级验收测试开始,然后逐步引入单元测试是如此重要。没有代码示例 - 抱歉,但你可以在Michael Feathers的书籍“与遗留代码有效地工作”中找到一堆示例。
此外,您还可以查看Legacy Code Retreat http://www.jbrains.ca/legacy-code-retreat 并寻找您所在地区的会议。