11

刚刚阅读了《重构:改进现有代码的设计》的前四章,我开始了我的第一次重构,但几乎立刻就遇到了障碍。它源于这样的要求,即在开始重构之前,您应该围绕遗留代码进行单元测试。这使您可以确保您的重构没有改变原始代码所做的事情(只是它是如何做的)。

所以我的第一个问题是:如何在遗留代码中对方法进行单元测试?如何围绕不只执行一项任务的 500 行(如果我幸运的话)方法进行单元测试?在我看来,我必须重构我的遗留代码才能使其可单元测试。

有没有人有使用单元测试重构的经验?如果是这样,你有什么实际的例子可以和我分享吗?

我的第二个问题有点难以解释。这是一个示例:我想重构一个从数据库记录中填充对象的遗留方法。难道我不需要编写一个单元测试来比较使用旧方法检索到的对象和使用重构方法检索到的对象吗?否则,我怎么知道我的重构方法会产生与旧方法相同的结果?如果这是真的,那么我要在源代码中保留旧的弃用方法多长时间?在我测试了几条不同的记录之后,我会直接敲它吗?或者,如果我在重构的代码中遇到错误,我是否需要保留一段时间?

最后,由于有几个人问过......遗留代码最初是用 VB6 编写的,然后移植到 VB.NET 中,架构更改最少。

4

7 回答 7

9

有关如何重构遗留代码的说明,您可能需要阅读《有效地使用遗留代码》一书。这里还有一个简短的 PDF 版本。

于 2009-02-06T22:22:40.880 回答
4

理论与现实相结合的好例子。单元测试旨在测试单个操作,许多模式纯粹主义者坚持Single Responsibilty,因此我们有可爱的干净代码和与之配套的测试。然而,在真实(混乱)的世界中,代码(尤其是遗留代码)做了很多事情并且没有测试。这需要进行重构以清理混乱。

我的方法是使用单元测试工具构建测试,在一个测试中测试很多东西。在一项测试中,我可能正在检查数据库连接是否打开,更改大量数据,并对数据库进行前后检查。我不可避免地会发现自己编写辅助类来进行检查,并且通常可以将这些辅助类添加到代码库中,因为它们封装了紧急行为/逻辑/需求。我并不是说我有一个巨大的测试,我的意思是mnay测试正在做一个纯粹主义者称之为集成测试的工作——这样的事情还存在吗?我还发现创建一个测试模板然后从中创建许多测试以检查边界条件、复杂处理等很有用。

顺便说一句,我们在谈论哪种语言环境?有些语言比其他语言更适合重构。

于 2009-02-06T22:08:21.300 回答
1

根据我的经验,我不会为遗留代码中的特定方法编写测试,而是为它提供的整体功能编写测试。这些可能会或可能不会与现有方法紧密映射。

于 2009-02-06T22:00:29.990 回答
1

在系统的任何级别编写测试(如果可以的话),如果这意味着运行数据库等,那就这样吧。您将需要编写更多代码来断言代码当前正在做什么,因为 500 行以上的方法可能会包含很多行为。至于比较新旧代码,如果您针对旧代码编写测试,它们就会通过并且涵盖了它所做的一切,那么当您针对新代码运行它们时,您实际上是在检查旧代码和新代码。我这样做是为了测试一个我想重构的复杂 sql 触发器,这很痛苦并且需要时间,但一个月后,当我们在该领域发现另一个问题时,值得在那里进行测试。

于 2009-02-06T22:08:57.587 回答
1

以我的经验,这是处理遗留代码时的现实。Esko 提到的 Book (Working with Legacy..) 是一部出色的作品,它描述了可以带您到那里的各种方法。

我已经看到了与单元测试本身类似的问题,它已经发展成为系统/功能测试。为 Legacy 或现有代码开发测试最重要的是定义术语“单元”。它甚至可以是“从数据库读取”等功能单元。识别关键功能单元并维护增加价值的测试。

顺便说一句,Joel S. 和 Martin F. 最近就 TDD/单元测试进行了讨论。我的看法是,定义单位并专注于它很重要!网址:公开信乔尔的成绩单播客

于 2009-02-07T06:29:04.220 回答
0

这确实是尝试修改遗留代码的关键问题之一。你能把问题域分解成更细化的东西吗?除了对 JDK/Win32/.NET Framework JAR/DLL/程序集的系统调用之外,这个 500 多行的方法是否会产生其他任何影响?即,您可以对 500 多行的庞然大物进行单元测试,是否有更精细的函数调用?

于 2009-02-06T21:59:59.087 回答
0

下面的书:单元测试的艺术包含几个章节,其中包含一些关于如何在开发单元测试方面处理遗留代码的有趣想法。

我发现它很有帮助。

于 2010-05-28T12:29:51.340 回答