单元测试能否成功添加到现有生产项目中?如果是这样,那么它是否值得?


140

我强烈考虑将单元测试添加到生产中的现有项目中。有人开始18个月前,我才真正看到TDD的任何好处(面对手掌),所以现在有一些项目一个相当大的解决方案,我一点都不知道知道哪里在添加单元测试开始。让我考虑的是,偶尔会出现一个老错误,或者将某个错误检查为已修复而没有真正修复。单元测试将减少或防止这些问题的发生。

通过阅读关于SO的类似问题,我看到了一些建议,例如从Bug跟踪程序开始,为每个Bug编写测试用例,以防止回归。但是,我担心如果我一开始就使用TDD,最终会错过总体情况,最终会错过一些基本测试。

是否应遵循任何流程/步骤,以确保对现有解决方案进行正确的单元测试,而不是仅仅纳入其中?我如何确保测试的质量很好,而不是任何测试的情况都比没有测试好

所以我想我也是在问:

  • 为生产中的现有解决方案付出努力值得吗?
  • 更好地忽略此项目的测试并在将来可能的重写中添加它吗?
  • 什么会更有益;花几个星期添加测试还是几个星期添加功能?

(显然,第三点的答案完全取决于您是在与管理人员还是开发人员对话)


赏金理由

增加赏金以尝试吸引更多答案,这不仅证实了我现有的怀疑,认为这是一件好事,而且也有一些反对的理由。

我的目的是稍后在正反两面写下这个问题,以试图向管理层表明,花很多工夫将产品的未来开发转移到TDD上是值得的。我想在没有我自己偏见的情况下应对这一挑战并发展我的推理。


11
强制性链接迈克尔羽毛在话题的书:amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/...
马克Rushakoff

1
@Mark-谢谢,它在我提供的链接中。我希望能得到一个体面的答案,而不必再购买其他书籍……尽管您永远不会拥有太多书籍(除非您想完成那本书)。
djdd87

1
您确实需要阅读这本书:)这是我的最爱之一,确实有助于理解重构和自动测试之间的紧张关系。
曼努埃尔·奥尔丹娜

Answers:


177

我已经将单元测试引入到以前没有的单元库中。当我到达团队时,我参与的最后一个大项目是产品在生产时已经进行了零单元测试。当我离开时-两年后-我们进行了4500多个测试,在具有230000 +生产LOC(实时财务Win-Forms应用程序)的代码库中,代码覆盖率约为33%。听起来可能很低,但是结果是代码质量和缺陷率有了显着提高-士气和盈利能力也得到了提高。

只要您对有关各方都具有正确的理解和承诺,就可以做到这一点。

首先,必须了解单元测试本身就是一项技能。您可以按照“常规”标准成为非常有生产力的程序员,而仍然难以以能够在较大项目中扩展的方式编写单元测试。

此外,特别针对您的情况,将单元测试添加到没有测试的现有代码库中本身也是一项专门技能。除非您或您的团队中的某人在将单元测试引入现有代码库方面具有成功的经验,否则我会读Feather的书(不是可选的,也不推荐这样做)。

向代码的单元测试过渡是对人员和技能的投资,就像对代码库质量的投资一样。就心态和管理期望而言,了解这一点非常重要。

现在,对于您的评论和问题:

但是,我担心如果最终从一开始就使用TDD,最终会错过总体情况,最终会错过一些基本测试。

简短的回答:是的,您会错过测试,是的,它们最初可能看起来不像在绿色田野中的情况。

更深层次的答案是:没关系。您从没有测试开始。开始添加测试,然后进行重构。随着技能水平的提高,开始提高添加到项目中的所有新编写代码的标准。持续改进等...

现在,在两行之间阅读时,我得到的印象是,这种思想来自“完美作为不采取行动的借口”的思想。更好的心态是专注于自我信任。因此,由于您可能尚不知道该怎么做,因此您将找出解决方法,并填补空白。因此,没有理由担心。

再次,它是一种技巧。您不能以一种线性方式从一种“过程”或“循序渐进”的“烹饪书”方法从零测试过渡到TDD完美。这将是一个过程。您的期望必须是逐步和逐步的进步与改进。没有神奇的药丸。

好消息是,随着几个月(甚至几年)的过去,您的代码将逐渐开始成为“适当的”经过良好分解和测试的代码。

作为旁注。您会发现在旧代码库中引入单元测试的主要障碍是缺乏内聚力和过多的依赖关系。因此,您可能会发现,最重要的技能将变成如何打破现有的依赖关系和解耦代码,而不是自己编写实际的单元测试。

是否应遵循任何流程/步骤,以确保对现有解决方案进行正确的单元测试,而不是仅仅局限于其中?

除非您已经拥有它,否则请设置构建服务器并设置一个持续集成的构建,该集成将在每个签入(包括具有代码覆盖率的所有单元测试)上运行。

训练你的人。

从客户的角度出发,在某处开始并开始添加测试(请参见下文)。

使用代码覆盖率作为测试您的生产代码库的指导性参考。

建立时间应始终为FAST。如果您的构建时间很慢,那么您的单元测试技能就会落后。找到较慢的测试并加以改进(解耦生产代码并单独进行测试)。写得好,您应该能够进行数千个单元测试,并且仍然可以在10分钟内完成构建(〜1毫秒/测试是一个很好的方法,但是非常粗糙,可能会出现一些例外情况,例如使用反射的代码等) )。

检查并适应。

如何确保测试的质量好,而不仅仅是任何测试的总比没有测试要好。

您自己的判断必须是现实的主要来源。没有可以取代技能的指标。

如果您没有这样的经验或判断力,请考虑与有经验的人签约。

总的代码覆盖率和构建速度是两个粗略的辅助指标。

为生产中的现有解决方案付出努力值得吗?

是。在定制的系统或解决方案上花费的绝大部分钱是在投入生产后花费的。而且,对质量,人员和技能的投资绝不应该过时。

更好地忽略此项目的测试并在将来可能的重写中添加它吗?

您不仅要考虑对人员和技能的投资,而且还必须考虑总拥有成本和系统的预期使用寿命。

在大多数情况下,我个人的回答是“当然可以”,因为我知道它要好得多,但我知道可能会有例外。

什么会更有益;花几个星期添加测试还是几个星期添加功能?

都不行 当您在功能方面取得进步时,您的方法应该是在代码库中添加测试。

同样,这是对人员,技能和代码库质量的投资,因此将需要时间。团队成员需要学习如何打破依赖关系,编写单元测试,学习新习惯,提高纪律和质量意识,如何更好地设计软件等。重要的是要了解,当您开始添加测试时,团队成员可能不会拥有这些技能,但要使该方法成功,就必须具备这些技能,因此,停止进度花费所有时间来添加很多测试根本是行不通的。

而且,将单元测试添加到任何规模可观的项目规模的现有代码库中都是一项艰巨的任务,需要投入和坚持。您不能改变一些基本的东西,在途中需要大量学习,并要求您的赞助商不要通过停止业务价值流来期望任何投资回报。那不会飞,坦白说不会。

第三,您想在团队中灌输合理的业务重点价值观。质量永远不会以牺牲客户为代价,没有质量就无法走得快。此外,客户生活在一个瞬息万变的世界中,而您的工作就是使客户更容易适应。与客户保持一致需要质量和业务价值流。

您正在做的是还清技术债务。您这样做的同时仍在满足不断变化的需求的客户。随着债务的偿还,情况逐渐改善,更容易为客户提供更好的服务并提供更多的价值。等等。这种积极的动力是您的目标,因为它强调了可持续发展步伐的原则,并将维护和改善道德–无论是对于您的开发团队,您的客户还是您的利益相关者。

希望能有所帮助


反映出与我相同的心态。当前,我正在展示此确切的过程/方法,以在大型JAVA应用程序中引入测试用例。:)
Darshan Joshi

3
对于我在Stackoverflow上阅读过的任何主题,这都是最清晰的答案。做得好!如果您还没有这样做,我敦促您考虑就最后一个问题的答案写一本书。
Yermo Lamers

谢谢耶尔莫。我不确定我是否有时间写书。但是也许我可以写一篇或两篇博客文章。刚开始我的新博客,可能还需要一段时间。
Mahol25 '18

2
这些花哨的单元测试建议是一般的寿命建议。说真的
Wjdavis5

24
  • 为生产中的现有解决方案付出努力值得吗?

是!

  • 更好地忽略此项目的测试并在将来可能的重写中添加它吗?

没有!

  • 什么会更有益;花几个星期添加测试还是几个星期添加功能?

添加测试(尤其是自动化测试)使将来使项目继续运行变得容易得多,并且大大减少了将愚蠢的问题发送给用户的可能性。

先验检验是检查您认为代码(以及其中的每个模块)的公共接口是否按照您的想法工作的测试。如果可以的话,还尝试诱导代码模块应该具有的每个独立的故障模式(请注意,这可能是不平凡的,并且应小心不要过分仔细地检查事情是如何失败的,例如,您不是真的想要做一些事情,例如计算由于失败而产生的日志消息的数量,因为验证是否已记录日志消息就足够了)。

然后针对您的错误数据库中的每个当前错误进行测试,以准确地找出错误,并在修复错误后通过。然后修复这些错误!:-)

添加测试确实需要花费时间,但是由于您的代码质量更高,因此您在后端获得了很多回报。当您尝试发布新版本或进行维护时,这非常重要。


感谢您的精心答复。确认我的感觉。在投我的票并接受之前,将看到发布了其他答案。
djdd87

15

改造单元测试的问题是您将意识到自己并没有考虑在此处注入依赖项或在此处使用接口,不久之后您将重写整个组件。如果有时间这样做,您将为自己建立一个不错的安全网,但是在此过程中可能会引入一些细微的错误。

从第一天开始,我就参与了许多真正需要单元测试的项目,没有简单的方法可以将它们放入其中,而没有一个完整的重写,通常在代码正常工作并且已经赚钱的时候就无法证明这一点。最近,我采取了编写Powershell脚本的方式来执行代码,以便在缺陷出现时立即重现缺陷,然后将其保留为一组回归测试,以便进一步进行更改。这样,您至少可以开始为应用程序构建一些测试,而无需对其进行太多更改,但是,与适当的单元测试相比,这些测试更像是端到端回归测试。


如果从一开始就对代码进行了合理的划分,那么对其进行测试就相当容易。问题出在您将所有代码杂乱地缝合在一起并且暴露的唯一测试点是完整集成测试时。(我有这样的代码,其中可测试性几乎为零,这是因为它依赖于其他不容易模拟的组件,并且部署需要重新启动服务器。可测试……但做得不好。)
Donal Fellows

13

我同意大多数人所说的话。向现有代码添加测试非常有价值。我永远不会不同意这一点,但是我想补充一点。

尽管在现有代码中添加测试很有价值,但确实要付出一定的代价。它以建立新功能为代价。这两件事如何平衡完全取决于项目,并且有很多变量。

  • 您需要花多长时间测试所有这些代码?天?几周?几个月?年份?
  • 您为谁编写此代码?付费客户?一位教授?一个开源项目?
  • 您的日程安排如何?您是否有必须满足的严格期限?您有最后期限吗?

再次强调一下,测试很有价值,您应该努力对旧代码进行测试。这实际上与您如何处理有关。如果您有能力删除所有内容并测试所有旧代码,请执行此操作。如果那是不现实的,那么至少这是您应该做

  • 您编写的任何新代码都应完全经过单元测试
  • 您碰巧碰到的所有旧代码(错误修复,扩展等)都应接受单元测试

同样,这不是一个全有或全无的主张。如果您有一个由四个人组成的团队,并且可以让一个或两个人执行遗留测试任务,那么您可以按时完成任务。

编辑:

我的目的是稍后在正反两面写下这个问题,以试图向管理层表明,花很多工夫将产品的未来开发转移到TDD上是值得的。

这就像问“使用源代码管理有什么优缺点?” 或“雇用人员之前与他们进行面谈的利弊是什么?” 或“呼吸的利弊是什么?”

有时,论点只有一方面。 您需要对任何复杂的项目进行某种形式的自动化测试。不,测试不会自行编写,是的,要花一些时间才能把事情弄清楚。但是,从长远来看,比事前编写测试要花费更多的时间,并且要花费更多的时间来纠正错误。 期。这里的所有都是它的。


9

当我们开始添加测试时,它是使用了十年的,大约一百万行的代码库,UI和报告代码中的逻辑太多了。

我们的第一件事(在设置连续构建服务器之后)是添加回归测试。这些是端到端测试。

  • 每个测试套件都通过将数据库初始化为已知状态开始。实际上,我们有数十个回归数据集保留在Subversion中(由于规模庞大,它与代码位于单独的存储库中)。每个测试的FixtureSetUp将这些回归数据集之一复制到一个临时数据库中,然后从那里运行。
  • 然后,测试装置设置程序将运行我们感兴趣的结果某些过程。(此步骤是可选的-某些回归测试仅用于测试报告。)
  • 然后,每个测试将运行一个报告,将该报告输出到.csv文件,并将该.csv的内容与保存的快照进行比较。这些快照.csvs存储在每个回归数据集旁边的Subversion中。如果报告输出与保存的快照不匹配,则测试失败。

回归测试的目的是告诉您是否有所变化。这意味着如果您破坏了某些内容,它们将失败,但是如果您有意更改了某些内容,它们也将失败(在这种情况下,解决方法是更新快照文件)。您甚至不知道快照文件是正确的-系统中可能存在错误(然后修复这些错误时,回归测试将失败)。

然而,回归测试对我们来说是一个巨大的胜利。我们系统中的几乎所有内容都有报告,因此通过花几周的时间对报告进行测试,我们可以在很大一部分代码库中获得一定程度的覆盖。编写等效的单元测试将花费数月或数年。(单元测试本来可以为我们提供更好的覆盖范围,并且本来就不那么脆弱;但是我宁愿现在拥有一些东西,而不是等待数年才能达到完美。)

然后我们回过头来,在修复错误或添加增强功能或需要了解一些代码时开始添加单元测试。回归测试绝不会消除对单元测试的需求;它们只是一级安全网,因此您可以快速获得一定水平的测试覆盖率。然后,您可以开始重构以打破依赖关系,从而可以添加单元测试。回归测试使您确信重构不会破坏任何东西。

回归测试存在一些问题:它们运行缓慢,并且有太多原因会导致破坏。但是至少对于我们来说,他们是如此值得。在过去的五年中,他们已经捕获了无数错误,并且他们在几个小时内就捕获了它们,而不是等待质量检查周期。我们仍然有那些原始的回归测试,分布在七台不同的连续构建机器上(与运行快速单元测试的机器分开),我们甚至不时增加它们,因为我们仍然有太多的代码以至于我们有6,000个+单元测试不包括在内。


8

绝对值得。我们的应用程序具有复杂的交叉验证规则,最近我们不得不对业务规则进行重大更改。我们最终因冲突而导致用户无法保存。我意识到在应用程序中进行分类可能要花很多时间(要花几分钟才能找到问题所在)。我想引入自动化的单元测试并安装了框架,但是除了进行一些虚拟测试以确保一切正常之外,我没有做任何其他事情。有了新的业务规则,我开始编写测试。测试迅速确定了导致冲突的条件,并且我们能够弄清规则。

如果编写涵盖要添加或修改的功能的测试,您将立即受益。如果等待重写,则可能永远不会进行自动测试。

您不应该花很多时间为已经存在的现有功能编写测试。大多数时候,您没有针对现有代码的规范,因此要测试的主要内容是逆向工程能力。另一方面,如果您要修改某些内容,则需要通过测试覆盖该功能,以便您正确地进行了更改。当然,对于新功能,编写失败的测试,然后实施缺少的功能。


6

我会加我的声音说是的,这总是很有用的!

但是,您应该记住一些区别:黑盒与白盒,单元与功能。由于定义各不相同,因此我的意思是:

  • 黑盒 =在没有特殊实现知识的情况下编写的测试,通常在边缘情况下四处寻找以确保事情能够像天真的用户所期望的那样发生。
  • 白盒 = 实现知识编写的测试,通常会尝试执行众所周知的故障点。
  • 单元测试 =单个单元(功能,可分离模块等)的测试。例如:确保数组类按预期工作,并且字符串比较函数返回各种输入的预期结果。
  • 功能测试 =一次对整个系统进行测试。这些测试将一次运行整个系统的很大一部分。例如:初始化,打开连接,执行一些实际操作,关闭,终止。我喜欢区分这些测试和单元测试,因为它们的目的不同。

当我在游戏后期将测试添加到运输产品中时,我发现白盒测试功能测试能带来最大的收益。如果您知道代码的任何部分特别脆弱,请编写白盒测试来涵盖问题案例,以确保代码不会两次以相同的方式破坏。同样,整个系统的功能测试是一个有用的完整性检查,可帮助您确保您从未破坏过10个最常见的用例。

小单元的黑匣子测试和单元测试也很有用,但是如果时间有限,最好尽早添加它们。到发货时,您通常已经(很难)找到了这些测试所能发现的大多数边缘情况和问题。

像其他人一样,我也会提醒您有关TDD的两个最重要的事情:

  1. 创建测试是一项持续的工作。它永远不会停止。每次编写新代码或修改现有代码时,都应尝试添加新测试。
  2. 您的测试套件绝对可靠!不要让您拥有测试的事实使您陷入错误的安全感。仅仅因为它通过了测试套件并不意味着它可以正常工作,或者您还没有引入微妙的性能下降等。

4

是否值得在生产中的应用程序中添加单元测试取决于维护应用程序的成本。如果应用程序中的错误和增强请求很少,那么可能就不值得这样做。OTOH,如果应用程序有错误或经常修改,则单元测试将非常有益。

在这一点上,请记住,我所说的是有选择地添加单元测试,而不是试图生成类似于您从一开始就实践TDD的测试套件。因此,针对第二个问题的后半部分:指出在下一个项目中使用TDD,无论是新项目还是重写项目(抱歉,但这是指向您确实应该阅读的另一本书的链接):通过测试引导不断发展的面向对象软件

我对第三个问题的回答与第一个问题相同:这取决于项目的上下文。

在你嵌入式职位是确保任何改装测试做了进一步的问题正确。要确保的重要一点是,单元测试实际上就是单元测试,并且(通常)意味着改装测试需要重构现有代码以允许层/组件的解耦(参见依赖注入;控制反转;存根;等等)。嘲笑)。如果您不能强制执行此操作,则您的测试将成为集成测试,这是有用的,但比真正的单元测试更具针对性,而且更脆弱。


4

您没有提到实现语言,但是如果使用Java,则可以尝试以下方法:

  1. 在单独的源代码树中,使用工具生成回归测试或“烟雾”测试,以生成测试,这可能使您接近80%的覆盖率。这些测试将执行所有代码逻辑路径,并从那时开始验证代码仍完全按照当前的方式运行(即使存在错误)。这为您提供了一个安全网,可防止在进行必要的重构以使代码易于手动进行单元测试时无意间改变行为。

  2. 对于从现在开始修复的每个错误或从现在开始添加的功能,请使用TDD方法来确保将新代码设计为可测试的,并将这些测试放在正常的测试源树中。

  3. 作为添加新功能的一部分,可能还需要更改或重构现有代码以使其可测试。您的烟雾测试将为您提供安全网,以防止行为退化或无意间发生细微变化。

  4. 通过TDD进行更改(错误修复或功能)时,完成后可能会伴随烟雾测试失败。验证由于所做的更改而导致的故障符合预期,并删除可读性较差的烟雾测试,因为您的手写单元测试已全面涵盖了该改进组件。确保您的测试覆盖率不会下降,而是保持不变或增加。

  5. 修复错误时,编写失败的单元测试,该测试将首先暴露该错误。


3

首先,我想说的是单元测试非常重要,因为它可以帮助您在错误蔓延到生产环境之前将其捕获。

确定重新引入了错误的区域项目/模块。从那些项目开始编写测试。为新功能和错误修复编写测试非常有意义。

为生产中的现有解决方案付出努力值得吗?

是。您会看到错误产生的影响,维护变得更加轻松

更好地忽略此项目的测试并在将来可能的重写中添加它吗?

我建议从现在开始。

什么会更有益;花几个星期添加测试还是几个星期添加功能?

您在问错问题。绝对,功能比什么都重要。但是,您应该问一下,花几周时间添加测试是否会使我的系统更稳定。这对我的最终用户有帮助吗?它将帮助团队中的新开发人员了解项目,并确保他/她由于对变更的总体影响缺乏了解而不会引入错误。


3

我非常喜欢“ 重构低垂的果实”作为对从哪里开始重构的问题的回答。这是一种轻松进行更好的设计而又不会花费太多精力的方法。

我认为同样的逻辑也适用于TDD-或仅适用于单元测试:根据需要编写所需的测试;为新代码编写测试;为出现的错误编写测试。您担心忽略代码库中难以到达的区域,这无疑是一种风险,但是作为入门的一种方法:入门!您可以使用代码覆盖工具来减轻风险,无论如何(我认为),风险并没有那么大:如果您覆盖了错误,覆盖了新代码,覆盖了正在查看的代码,那么您将涵盖最需要测试的代码。


2
  • 是的。当您开始添加新功能时,可能会导致对旧代码进行一些修改,从而导致潜在的错误。
  • (请参阅第一个)在开始添加新功能之前,所有(或几乎)代码(理想情况下)都应包含在单元测试中。
  • (请参阅第一个和第二个):)。新的宏伟功能可以“破坏”旧的工作代码。

2

是的,它可以:仅尝试确保您现在编写的所有代码均已进行测试。

如果需要修改已经可以使用的代码,并且可以对其进行测试,则可以这样做,但是最好不要过于努力尝试对稳定的代码进行测试。这种事情往往会产生连锁反应,并可能失控。


2

为生产中的现有解决方案付出努力值得吗?
是。但是您不必编写所有单元测试就可以开始。只需将它们一一添加。

更好地忽略此项目的测试并在将来可能的重写中添加它吗?
不会。第一次添加破坏功能的代码时,您会后悔的。

什么会更有益;花几个星期添加测试还是几个星期添加功能?
对于新功能(代码),这很简单。首先编写单元测试,然后编写功能。对于旧代码,您可以决定方法。您不必所有单元测试都到位...添加那些对您最没有伤害的单元测试...时间(和错误)将告诉您必须重点关注哪一个;)


2

更新资料

最初回答的6年后,我的看法有所不同。

我认为将单元测试添加到您编写的所有新代码中是有道理的,然后重构您进行更改以使其可测试的位置。

一劳永逸地为所有现有代码编写测试无济于事-但为编写的新代码(或修改的区域)编写测试也不可行。在重构/添加事物时添加测试可能是添加测试并使代码在没有测试的现有项目中更易于维护的最佳方法。

较早的答案

我会在这里引起一些注意:)

首先,您的项目是什么-如果它是编译器,语言,框架或其他在很长一段时间内不会改变功能的项目,那么我认为添加单元测试绝对很棒。

但是,如果您正在开发可能需要更改功能的应用程序(因为需求不断变化),那么就无需付出额外的努力。

为什么?

  1. 单元测试仅涵盖代码测试-代码是否符合设计的目的-不能替代必须进行的手动测试(以发现功能错误,可用性问题和所有其他类型的问题)

  2. 单元测试花费时间!现在我来自哪里,那是一种宝贵的商品-商业通常会在一个完整的测试套件上选择更好的功能。

  3. 如果您的应用程序甚至对用户远程有用,他们将请求更改-因此您将拥有可以更好,更快地完成工作的版本,并且可能还会做新的事情-随着代码的增长,可能还会进行大量重构。在动态环境中维护完整的单元测试套件令人头疼。

  4. 单元测试不会影响产品的感知质量-用户看到的质量。当然,您的方法可能与第1天完全一样,表示层和业务层之间的接口可能很原始-但是您猜怎么着?用户不在乎!找一些真正的测试人员来测试您的应用程序。而且,这些方法和接口通常迟早都必须进行更改。

什么会更有益;花几个星期添加测试还是几个星期添加功能?-有很多事情比编写测试要好得多-编写新功能,提高性能,提高可用性,编写更好的帮助手册,解决未解决的错误等。

现在不要误会我的意思-如果您完全肯定未来100年不会发生任何变化,请继续进行下去,写下自己的测试。自动化测试对于API也是一个好主意,因为您绝对不想破坏第三方代码。在其他任何地方,这只是让我稍后发货的原因!



您是要“修复未解决的错误”还是要防止它们发生?适当的单元测试可以通过最大程度地减少错误修复所花费的时间,从而节省时间。
伊霍尔·卡哈利钦科

那是个神话。如果您告诉我自动化的单元测试可以代替手动测试,那么您会感到非常严重的错误。如果没有错误,手动测试人员会记录什么?
Roopesh Shenoy

是的,请不要误解我的意思-我并不是说单元测试绝对是浪费-重点是考虑编写它们所需的时间以及在更改产品时可能必须更改的原因,它们真的会有所回报。对我来说,我已经尝试了双方,但答案是否定的,他们没有足够快地偿还债务。
Roopesh Shenoy

1

您不太可能拥有大量的测试范围,因此您必须在添加测试位置方面具有战术性:

  • 正如您提到的,发现错误时,是编写测试(再现它)并修复该错误的好时机。如果您看到该测试重现了该错误,则可以确定它是一个不错的测试。鉴于大部分错误是回归(50%?),几乎总是值得编写回归测试。
  • 当您深入研究代码区域以进行修改时,现在是围绕它编写测试的好时机。根据代码的性质,不同的测试是合适的。在这里可以找到一套很好的建议。

OTOH,仅仅围绕人们满意的代码编写测试是不值得的-尤其是如果没人打算修改它时。它只是没有增加价值(除了可能了解系统的行为之外)。

祝好运!



1

如果我在您的位置,那么我可能会采取一种由内而外的方法,首先是对整个系统进行功能测试。我将尝试使用像RSpec这样的BDD规范语言来重新记录系统的需求,然后编写测试以通过自动化用户界面来验证那些需求。

然后,我将对新发现的错误进行缺陷驱动的开发,编写单元测试以重现问题,然后对错误进行处理,直到测试通过。

对于新功能,我会坚持采用由外而内的方法:从RSpec中记录的功能开始,并通过自动化用户界面进行验证(当然,这些功能最初会失败),然后在实现过程中添加更细粒度的单元测试。

我不是这个过程的专家,但是根据我的经验,我可以告诉您通过自动UI测试进行BDD并不容易,但是我认为这是值得的,并且可能会为您带来最大的收益。


1

无论如何,我都不是经验丰富的TDD专家,但是我想说的是,尽可能多地进行单元测试非常重要。由于代码已经到位,所以我将从获得某种单元测试自动化开始。我使用TeamCity在项目中进行所有测试,它为您提供了有关组件工作方式的不错总结。

有了这些,我将继续研究那些不会失败的非常关键的类似业务逻辑的组件。就我而言,对于各种输入,需要解决一些基本的三角学问题,因此,我测试了这些问题。我这样做的原因是,当我燃烧午夜的油时,很容易浪费时间去挖掘真正不需要触及的代码深度,因为您知道它们已经针对所有可能的输入进行了测试。 (在我的情况下,输入的数量是有限的)。

好的,现在希望您对这些关键部分感到满意​​。与其坐下来并展开所有测试,不如在测试出现时攻击它们。如果您遇到的错误是真正要修复的PITA,请为其编写单元测试,并避免使用它们。

在某些情况下,您会发现测试很困难,因为您无法从测试中实例化特定的类,因此必须对其进行模拟。哦,但是也许您不能轻松地模拟它,因为您没有写接口。我将这些“ whoops”场景作为实现上述接口的机会,因为,这是一件好事。

从那里,我将为您的构建服务器或配置有代码覆盖工具的任何自动化设备。它们会创建覆盖范围很广的红色大区域的讨厌条形图。现在100%的覆盖率不是您的目标,也不是100%的覆盖率不一定意味着您的代码是防弹的,但是当我有空闲时间时,红色的确会激励我。:)


1

有很多好的答案,所以我不再重复它们的内容。我检查了您的个人资料,看来您是C#.NET开发人员。因此,我添加了对Microsoft PEX和Moles项目的引用,可以帮助您自动生成遗留代码的单元测试。我知道自动生成不是最好的方法,但至少是开始的方法。请查阅MSDN杂志上有关将PEX用于旧代码的非常有趣的文章。


1

我建议阅读TopTal工程师的精彩文章,其中解释了从哪里开始添加测试:它包含许多数学,但是基本思想是:

1)测量代码的传入耦合(CA)(一个类被其他类使用了多少,这意味着破坏它会造成广泛的破坏)

2)测量您的代码的循环复杂度(CC)(更高的复杂度=更高的中断更改)

您需要确定具有较高CA和CC的类,即具有函数f(CA,CC),并且应将两个度量标准之间差异最小的类的测试覆盖范围赋予最高优先级。

为什么?因为较高的CA等级但非常低的CC等级非常重要,但不太可能打破。另一方面,较低的CA但较高的CC可能会破坏,但损害较小。所以你想保持平衡。


0

这取决于...
进行单元测试非常好,但是您需要考虑您的用户是谁,以及他们愿意容忍什么才能获得更加安全的产品。不可避免地,通过重构当前没有任何单元测试的代码,您将引入错误,并且许多用户将很难理解您正在暂时使产品变得更加有缺陷,从长远来看使其具有更少的缺陷。最终,拥有最终决定权的是用户...


-2

是。否。添加测试。

朝着更TDD的方向发展实际上将更好地指导您添加新功能并简化回归测试的工作。看看这个!

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.