单元测试可以成功地添加到现有的生产项目中吗? 如果可以,它是如何和是否值得?

我正在强烈考虑将单元测试添加到生产中的现有项目中。它是在18个月前开始的,那时我还没有真正看到 TDD (掌心)的任何好处,所以现在它是一个有着许多项目的大型解决方案,而且我也不知道从哪里开始添加单元测试。让我思考这个问题的原因是,有时候一个旧的 bug 似乎会重新出现,或者一个 bug 在没有修复 真的的情况下被签入为已修复。单元测试可以减少或防止这些问题的发生。

通过阅读关于 SO 的 < a href = “ https://stackoverflow. com/questions/1046816/adding- unit-test- to-an-already-asp-net-web-forms-application”> 相似的 问题,我看到了一些建议,比如从 bug 跟踪器开始,为每个 bug 编写一个测试用例以防止回归。然而,我担心我最终会错过整体情况,并且最终会错过一些基本的测试,如果我从一开始就使用 TDD 的话,这些测试就会包含在测试中。

为了确保现有的解决方案是经过 适当地单元测试的,而不仅仅是被卡在里面,是否有任何过程/步骤需要遵守?我怎样才能确保测试的质量是好的,而不仅仅是一个案例 总比没有好

所以我想问的是

  • 是否值得为了一个 正在生产的现有解决方案?
  • 是不是忽略这些测试 并将其添加到 可能的未来重写?
  • 什么更有益; 花费 几个星期增加一些测试或一些 增加功能?

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


赏金理由

增加奖金,试图吸引更广泛的答案,不仅证实了我现有的怀疑,这是一件好事,但也有一些很好的理由反对。

我的目标是在稍后写出这个问题的正反两方面,以试图向管理层表明,将产品的未来开发转移到 TDD 是值得花费人力时间的。我想接近这个挑战,发展我的推理没有我自己的偏见的观点。

25566 次浏览
  • 对于正在生产中的现有解决方案,是否值得付出努力?

太棒了!

  • 是否忽略该项目的测试并将其添加到未来可能的重写中更好?

不!

  • 花几周时间添加测试,还是花几周时间添加功能,哪个更有益?

添加测试(特别是自动化测试)使得 很多更容易在未来保持项目的工作,并且极大地降低了将愚蠢的问题发送给用户的可能性。

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

然后对 bug 数据库中的每个当前 bug 进行一次测试,该测试将准确地引发 bug,并在 bug 修复后通过。那就修好那些虫子!:-)

添加测试确实需要预先花费一些时间,但是由于代码的质量要高得多,所以在后端会多次得到回报。当您试图发布新版本或进行维护时,这一点非常重要。

  • 是的。当您开始添加新的功能时,它可能会导致一些旧的代码修改,结果是潜在的 bug 的来源。
  • 在开始添加新功能之前(参见第一个) ,所有(或几乎)代码(理想情况下)都应该被单元测试覆盖。
  • (参见第一个和第二个) : 。一个新的宏伟的功能可以“摧毁”旧的工作代码。

改进单元测试的问题在于,你会意识到你没有在这里注入一个依赖项,或者在那里使用一个接口,不久你就会重写整个组件。如果你有时间这样做,你会为自己建立一个很好的安全网,但是你可以在这个过程中引入一些细微的错误。

我参与过很多项目,这些项目从一开始就需要单元测试,而且没有简单的方法把它们放进去,除非完全重写,当代码正在工作并且已经在赚钱的时候,这通常是不合理的。最近,我开始编写 Powershell 脚本,以一种一旦出现缺陷就立即重现的方式来运行代码,然后将这些脚本作为一套回归测试,以便进一步进行更改。这样,您至少可以开始为应用程序构建一些测试,而不需要对其进行太多的更改,但是,这些测试更像是端到端的回归测试,而不是正确的单元测试。

是的。 没有。 添加测试。

使用更多的 TDD 方法实际上可以更好地告知您添加新功能的努力,并使回归测试更加容易。看看这个!

是的,它可以: 只要确保从现在开始编写的所有代码都有一个测试就可以了。

如果已经到位的代码需要修改并且可以进行测试,那么就这样做,但是最好不要过于强烈地试图为稳定的代码进行测试。这类事情往往会产生连锁反应,并可能螺旋式地失去控制。

是否值得为正在生产的应用程序添加单元测试,取决于维护该应用程序的成本。如果应用程序有一些错误和增强的要求,那么也许它不值得努力。OTOH,如果应用程序有错误或经常修改,那么单元测试将是非常有益的。

此时,请记住我所说的是有选择地添加单元测试,而不是试图生成类似于如果您从一开始就练习 TDD 就会存在的那些测试套件。因此,回答你第二个问题的后半部分: 在你的下一个项目中使用 TDD,无论是一个新项目还是一个重写项目(抱歉,这里有一个 另一个书籍的链接,你真的应该读一读: 测试引导下的面向对象软件成长)

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

嵌入在你的职位是一个进一步的问题,以确保任何改装测试是做 正确地。重要的是要确保单元测试真的是 单位测试,这意味着改进测试需要重构现有的代码,以允许层/组件的解耦(参考依赖注入、控制反转、存根、模仿)。如果您不能强制执行,那么您的测试将成为集成测试,这是有用的,但与真正的单元测试相比,目标更少,也更脆弱。

绝对值得。我们的应用程序有复杂的交叉验证规则,最近我们不得不对业务规则进行重大修改。我们最终遇到了阻止用户保存的冲突。我意识到在应用程序中解决这个问题需要花费很长的时间(只需要几分钟就可以解决问题)。我想引入自动化的单元测试并安装框架,但是除了一些虚拟的测试以确保工作正常之外,我没有做任何事情。在掌握了新的业务规则之后,我开始编写测试。测试很快识别出引起冲突的条件,我们能够使规则得到澄清。

如果您编写的测试涵盖了您正在添加或修改的功能,那么您将立即受益。如果等待重写,则可能永远不会有自动化测试。

您不应该花费大量时间为已有的工作编写测试。大多数时候,您没有现有代码的规范,因此您测试的主要内容是您的逆向工程能力。另一方面,如果要修改某些内容,则需要用测试覆盖该功能,以便您知道所做的更改是正确的。当然,对于新功能,编写失败的测试,然后实现缺失的功能。

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

尽管向现有代码中添加测试是有价值的,但它也是有代价的。这是以 没有建立新功能为代价的。这两者如何平衡完全取决于项目,而且有很多变量。

  • 测试这些代码需要多长时间?几天?几周?几个月?几年?
  • 你在为谁写代码? 付费客户? 教授? 开源项目?
  • 你的日程安排是怎样的?你必须在最后期限前完成工作吗?你有截止日期吗?

同样,让我强调一下,测试是有价值的,您应该努力将您的旧代码置于测试之下。这实际上更多的是你如何处理它的问题。如果您能够放下一切并将所有旧代码都进行测试,那么就这样做吧。如果这不现实,这里是你应该做的 至少

  • 您编写的任何新代码都应该完全进行单元测试
  • 任何你碰巧碰到的旧代码(错误修复,扩展等)都应该进行单元测试

此外,这不是一个全有或全无的主张。如果您有一个四人团队,并且您可以通过让一两个人执行遗留测试任务来完成您的最后期限,那么请务必这样做。

编辑:

我的目标是在稍后写出这个问题的正反两方面,以试图向管理层表明,将产品的未来开发转移到 TDD 是值得花费人力时间的。

这就像问“使用源代码管理的利弊是什么?”或者“在雇人之前面试他们有什么好处和坏处?”或者“呼吸的好处和坏处是什么?”

有时候争论只有一方。您需要对任何复杂的项目进行某种形式的自动化测试。不,测试不会自己编写,而且,是的,需要一些额外的时间才能完成。但 从长远来看,在事后修复 bug 要比事先编写测试花费更多的时间和金钱。时期。就是这样。

首先我想说的是,单元测试非常重要,因为它将帮助您在 bug 进入生产环境之前阻止它们。

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

是否值得为现有的 正在生产的溶液?

是的。您将看到 bug 下降和维护变得更加容易的效果

是不是忽略这些测试 并将其添加到 可能的未来重写?

我建议从现在开始。

什么更有益; 花费 几个星期增加一些测试或一些 增加功能?

你问错问题了。毫无疑问,功能性比其他任何东西都重要。但是,你应该问,如果花几个星期添加测试将使我的系统更稳定。这对我的终端用户有帮助吗?它是否有助于团队中的新开发人员理解项目,并确保他/她不会因为缺乏对变更的整体影响的理解而引入 bug。

对于正在生产中的现有解决方案,是否值得付出努力?
是的,但是你不必编写所有的单元测试来开始,只需要一个一个地添加它们。

是否忽略该项目的测试并将其添加到未来可能的重写中更好?
不。第一次添加破坏功能的代码时,你会后悔的。

花几周时间添加测试,还是花几周时间添加功能,哪个更有益?
对于新的功能(代码) ,它很简单: 首先编写单元测试,然后编写功能。 对于旧代码,您可以在路上决定。你不必把所有的单元测试都安排到位... ... 添加那些对你最不利的单元测试... ... 时间(和错误)会告诉你应该关注哪个单元测试;)

您不太可能拥有显著的测试覆盖率,因此您必须对添加测试的位置有策略:

  • 正如您所提到的,当您发现一个 bug 时,是编写一个测试(重现它) ,然后修复这个 bug 的好时机。如果您看到测试重现了 bug,那么您可以确定它是一个好的、可靠的测试。鉴于如此大比例的错误是回归(50% ?),它几乎总是值得写回归测试。
  • 当您深入到一个代码区域来修改它时,就是围绕它编写测试的好时机。根据代码的性质,可以进行不同的测试。一套好的建议。

OTOH,它不值得只是坐在编写人们喜欢的代码周围的测试-特别是如果没有人会修改它。它只是没有增加价值(除了可能理解系统的行为)。

祝你好运!

我已经将单元测试引入到以前没有的代码库中。我参与的最后一个大项目是在哪里完成的,当我到达团队时,产品已经进入生产阶段,没有任何单元测试。当我离开时——两年后——我们有4500多个测试,在一个拥有230000多个生产 LOC (实时金融 Win-Forms 应用程序)的代码库中,产生了大约33% 的代码覆盖率。这听起来可能很低,但是结果是代码质量和缺陷率的显著改进——加上士气和盈利能力的提高。

当你有一个准确的理解和承诺,从有关各方可以做到这一点。

首先,理解单元测试本身就是一种技能是很重要的。按照“常规”标准,您可以成为一个非常高效的程序员,但仍然难以编写在较大项目中可伸缩的单元测试。

另外,特别是针对您的情况,向没有测试的现有代码库中添加单元测试本身也是一项专门技能。除非您或您的团队中的某人在向现有代码库引入单元测试方面有成功的经验,否则我认为阅读 费瑟的书是必需的(不是可选的或强烈推荐的)。

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

现在,欢迎大家提出意见和问题:

然而,我担心我最终会错过整体情况,并且最终会错过一些基本的测试,如果我从一开始就使用 TDD 的话,这些测试就会包含在测试中。

简短的回答: 是的,您将错过测试,而且是的,它们最初看起来可能不像绿色领域的情况。

更深层次的答案是: 这无关紧要。你从不做测试开始。开始添加测试,并随时重构。随着技能水平的提高,开始提高添加到项目中的所有新编写代码的门槛。不断改进等等。.

现在,从这里的字里行间,我得到的印象是,这是来自“完美作为不采取行动的借口”的心态。更好的心态是专注于自信。因此,你可能还不知道如何去做,你会找出如何去,并填补空白。因此,没有理由担心。

再说一次,这是一种技能。你不能从零测试到 TDD-在一个“过程”或“一步一步”的线性方式烹饪书方法的完美。这将是一个过程。你的期望必须是循序渐进的进步和改进。根本没有什么灵丹妙药。

好消息是,随着时间的推移,您的代码将逐渐开始成为“合适的”具有良好因素和经过良好测试的代码。

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

是否有任何过程/步骤需要遵守,以确保现有的解决方案经过了适当的单元测试,而不仅仅是卡在其中?

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

训练你的人。

从客户的角度出发,在取得进展的同时开始添加测试(见下文)。

使用代码覆盖率作为指导参考,了解有多少生产代码基础正在测试之中。

构建时间应该始终是快速的。如果您的构建时间很慢,那么您的单元测试技能就是滞后的。找到慢速测试并改进它们(解耦生产代码并单独进行测试)。写得好的话,你应该可以很容易地拥有几千个单元测试,并且在10分钟内完成一个构建(~ 1-几个 ms/test 是一个很好的但是非常粗略的指导方针,一些例外情况可能会适用,比如代码使用反射等)。

检查并适应。

我如何确保测试的质量是好的,并且不仅仅是任何测试的一个案例,总比没有测试要好。

你自己的判断力必须是你现实生活的主要来源。没有任何标准可以取代技能。

如果你没有这方面的经验或判断力,可以考虑找一个有这方面经验或判断力的人。

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

对于正在生产中的现有解决方案,是否值得付出努力?

是的。在定制构建的系统或解决方案上花费的大部分资金都是在它投入生产之后花费的。投资于质量、人员和技能永远不会过时。

是否忽略该项目的测试并将其添加到未来可能的重写中更好?

你不仅要考虑人力和技能的投资,还要考虑最重要的是所有权的总成本和系统的预期寿命。

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

花几周时间添加测试,还是花几周时间添加功能,哪个更有益?

都不是。您的方法应该是在功能方面取得进展的同时向代码库中添加测试。

同样,这是对人员、技能和代码库质量的投资,因此需要时间。团队成员需要学习如何打破依赖,编写单元测试,学习新的习惯,提高纪律和质量意识,如何更好地设计软件等等。重要的是要明白,当你开始添加测试时,你的团队成员可能还没有达到这种方法成功所需的水平,所以停止进度花费所有时间添加大量测试根本不会起作用。

此外,将单元测试添加到任何大型项目规模的现有代码库中都是一项需要承诺和持久性的大工程。你不能改变一些基本的东西,期望在途中学到很多东西,并要求你的赞助商不要期望通过停止业务价值的流动而获得任何投资回报率。那不会成功的,坦白说也不应该成功。

第三,你要向你的团队灌输合理的业务重点价值观。质量永远不会以牺牲顾客为代价,没有质量你就不能快速前进。此外,客户生活在一个不断变化的世界,你的工作是让他更容易适应。客户一致性要求质量和业务价值的流动。

你正在做的是偿还技术债务。而且你在这样做的同时仍然在为你的客户不断变化的需求服务。随着债务的偿还,情况逐渐改善,更好地为客户服务和提供更多价值变得更容易。等等。这种积极的动力是你应该追求的目标,因为它强调了可持续发展的原则,并将保持和提高道德-无论是对于你的开发团队,你的客户还是你的利益相关者。

希望能帮上忙

你说你不想再买一本书。看看迈克尔 · 费瑟在 有效地使用遗留代码上的文章吧。那就买这本书:)

我非常喜欢用 重构低悬的果实来回答从哪里开始重构的问题。这是一种轻松进入更好设计的方法,而不是贪多嚼不烂。

我认为同样的逻辑也适用于 TDD ——或者只是单元测试: 根据需要编写测试; 根据新代码编写测试; 根据出现的 bug 编写测试。您担心忽略代码库中难以到达的区域,这当然是一种风险,但是作为一种开始的方式: 开始吧!你可以通过代码覆盖工具来降低风险,而且风险(在我看来)也没有那么大: 如果你覆盖了 bug,覆盖了新代码,覆盖了你正在查看的代码,那么你就覆盖了最需要测试的代码。

我会加入我的声音,说是的,它总是有用的!

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

  • 黑盒 = 没有特殊实现知识就编写的测试,通常在边缘情况下进行检查,以确保事情按照天真的用户所期望的那样发生。
  • 白盒 = 编写了 实现知识的测试,这些知识通常试图练习众所周知的失败点。
  • 单元测试 = 单个单元(函数、可分离模块等)的测试。例如: 确保数组类按预期工作,字符串比较函数返回大范围输入的预期结果。
  • 功能测试 = 同时对整个系统进行测试。这些测试将同时运行系统的一大块。例如: init,打开一个连接,做一些实际的事情,关闭,终止。我喜欢将这些测试和单元测试区分开来,因为它们服务于不同的目的。

当我在游戏后期添加测试到发货产品时,我发现我从 白盒子功能性的测试中获得了最大的成本效益。如果您知道代码中有任何部分特别脆弱,那么编写白盒测试来覆盖问题情况,以帮助确保它不会以同样的方式出现两次故障。类似地,全系统功能测试是一种有用的健全性检查,它可以帮助您确保永远不会破坏10个最常见的用例。

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

和其他人一样,我还要提醒您 TDD 最重要的两点:

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

您没有提到实现语言,但是如果在 Java 中,您可以尝试这种方法:

  1. 在一个单独的源代码树中构建回归或“冒烟”测试,使用一个工具来生成它们,这可能使您的覆盖率接近80% 。这些测试执行所有的代码逻辑路径,并从这一点开始验证代码是否仍然执行当前的操作(即使存在 bug)。这为您提供了一个安全网,以防止在进行必要的重构时无意中改变行为,从而使代码易于手动进行单元测试。

  2. 对于您修复的每个 bug,或者从现在开始添加的特性,使用 TDD 方法来确保新代码的设计是可测试的,并将这些测试放在普通的测试源代码树中。

  3. 现有的代码也可能需要修改,或者重构,以便作为添加新特性的一部分使其可测试; 您的冒烟测试将为您提供一个安全网,防止回归或无意中对行为进行细微的改变。

  4. 当通过 TDD 进行更改(bug 修复或特性)时,当完成时,伴随的冒烟测试可能会失败。验证由于所做的更改而导致的故障是否与预期的一样,并删除可读性较差的冒烟测试,因为您手写的单元测试已经完全覆盖了改进的组件。确保您的测试覆盖率不会下降,只是保持不变或增加。

  5. 在修复 bug 时,编写一个首先暴露 bug 的失败单元测试。

如果我是你,我可能会采取由外向内的方法,从运行整个系统的功能测试开始。我会尝试使用像 RSpec 这样的 BDD 规约语言来重新记录系统的需求,然后通过自动化用户界面来编写测试来验证这些需求。

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

对于新特性,我将坚持由外向内的方法: 从 RSpec 中记录的特性开始,并通过自动化用户界面进行验证(当然最初会失败) ,然后随着实现的进展添加更多细粒度的单元测试。

我不是这个过程的专家,但是根据我的一点经验,我可以告诉你通过自动化 UI 测试进行 BDD 并不容易,但是我认为这是值得的,并且可能会在你的案例中产生最大的好处。

当我们开始添加测试时,它是一个十年前的,大约有百万行代码的基础,在 UI 和报告代码中有太多的逻辑。

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

  • 每个测试套件首先将数据库初始化为一个已知状态。实际上,我们在 Subversion 中保存了几十个回归数据集(由于规模庞大,它们位于代码的单独存储库中)。每个测试的 FixtureSetUp 将这些回归数据集中的一个复制到临时数据库中,然后从该数据库运行。
  • 测试夹具设置然后运行一些我们感兴趣的结果的过程。(这个步骤是可选的——一些回归测试仅用于测试报告。)
  • 然后每个测试运行一个报告,将报告输出到。Csv 文件,并比较该文件的内容。将 csv 转换为保存的快照。这些快照。Csv 存储在每个回归数据集旁边的 Subversion 中。如果报表输出与保存的快照不匹配,则测试失败。

回归测试的目的是告诉您是否发生了变化。这意味着,如果您破坏了某些内容,它们就会失败,但如果您故意更改了某些内容,它们也会失败(在这种情况下,修复方法是更新快照文件)。您甚至不知道快照文件是否正确——系统中可能存在 bug (当您修复这些 bug 时,回归测试将失败)。

然而,回归测试对我们来说是一个巨大的胜利。在我们的系统中,几乎所有的东西都有一个报告,所以通过花费几个星期的时间对报告进行测试,我们能够在一定程度上覆盖大部分的代码库。编写等效的单元测试可能需要几个月或几年的时间。(单元测试会给我们带来更好的覆盖率,也不会那么脆弱; 但我宁愿现在就有,而不是等待数年才能完美。)

然后我们回过头来,在修复 bug、添加增强或需要理解某些代码时,开始添加单元测试。回归测试并没有消除对单元测试的需求; 它们只是一个初级的安全网,因此您可以快速地获得 一些级别的测试覆盖率。然后可以开始重构以打破依赖关系,这样就可以添加单元测试; 回归测试可以让您确信重构不会破坏任何东西。

回归测试存在问题: 它们很慢,而且有太多的原因导致它们可能崩溃。但至少对我们来说,他们是值得的。在过去的五年里,他们抓住了无数的窃听器,而且他们在几个小时内就抓住了它们,而不是等待质量保证周期。我们仍然有那些原始的回归测试,分布在七个不同的连续构建机器上(与运行快速单元测试的机器分开) ,我们甚至不时地添加它们,因为我们仍然有太多的代码,我们的6000多个单元测试不能覆盖。

更新

6年后的原始答案,我有一个略有不同的看法。

我认为向您编写的所有新代码中添加单元测试是有意义的——然后重构您进行更改的位置,以使它们可测试。

一次性为所有现有代码编写测试没有帮助,但是不为所编写的新代码(或修改的区域)编写测试也没有意义。在重构/添加内容时添加测试可能是添加测试的最佳方式,并且可以使代码在没有测试的现有项目中更易于维护。

早期答案

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

首先,你的项目是什么——如果它是一个编译器、一种语言、一个框架或者其他任何在很长一段时间内功能上不会改变的东西,那么我认为增加单元测试是绝对不可思议的。

但是,如果您正在开发的应用程序可能需要更改功能(因为更改了需求) ,那么就没有必要进行额外的工作。

为什么?

  1. 单元测试只覆盖代码测试——不管代码是否按照设计要求运行——它不能取代手工测试,手工测试无论如何都是必须要做的(为了发现功能性错误、可用性问题和所有其他类型的问题)

  2. 单元测试花费时间!在我的家乡,这是一种珍贵的商品——而且业务通常会选择比一个完整的测试套件更好的功能。

  3. 如果你的应用程序对用户来说有用的话,他们会要求更改——所以你的版本会做得更好,更快,可能还会做新的事情——随着代码的增长,可能还会有很多重构。在动态环境中维护完整的单元测试套件是一个令人头疼的问题。

  4. 单元测试不会影响产品的感知质量——用户看到的质量。当然,您的方法可能与第一天一模一样,表示层和业务层之间的接口可能是原始的——但是你猜怎么着?用户不在乎!找一些真正的测试人员来测试您的应用程序。而且通常情况下,这些方法和接口无论如何都必须改变,这是迟早的事。

花几周时间添加测试,还是花几周时间添加功能,哪个更有益?- 有很多事情你可以做的比写测试更好-写新的功能,提高性能,改善可用性,写更好的帮助手册,解决悬而未决的错误,等等。

现在,不要误解我的意思——如果你对未来100年的情况不会改变持绝对肯定的态度,那么就继续吧,尽情地写这些测试吧。对于 API 来说,自动化测试也是一个很好的想法,因为您绝对不希望破坏第三方代码。在其他地方,这只是一些让我船以后!

看情况。
拥有单元测试很棒,但是你需要考虑你的用户是谁,以及他们愿意容忍什么,这样才能得到一个没有 bug 的产品。通过重构目前还没有单元测试的代码,不可避免地会引入 bug,许多用户会发现很难理解你正在让产品暂时更有缺陷,以便从长远来看减少缺陷。最终,用户将拥有最终的发言权。

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

有了这些,我就可以转向那些真正关键的业务逻辑——比如不会失败的组件。在我的例子中,有一些基本的三角函数问题需要为不同的输入解决,所以我测试了这些问题。我这样做的原因是,当我开夜车的时候,很容易浪费时间去深入挖掘那些真的不需要去触摸的代码,因为所有可能的输入都是 知道他们经受了考验(在我的例子中,输入的数量是有限的)。

好了,希望你现在对那些关键的部分感觉好点了。而不是坐下来敲出所有的测试,我会攻击他们,因为他们出来了。如果遇到一个真正的 PITA 需要修复的 bug,那么为它编写单元测试,并将它们排除在外。

在某些情况下,您会发现测试很困难,因为您不能从测试中实例化特定的类,所以您必须模仿它。哦,但也许你不能轻易嘲笑它,因为你没有写入一个接口。我把这些“哎呀”场景作为实现所述接口的机会,因为,嗯,这是一件好事。

从那里,我将得到您的构建服务器或任何配置了代码覆盖工具的自动化。他们创建讨厌的条形图与大红色区域,你有贫穷的覆盖率。现在100% 的覆盖率并不是你的目标,也不一定意味着你的代码是防弹的,但是红色的条肯定会在我有空的时候激励我。:)

有这么多好的答案,所以我不会重复他们的内容。我查了你的资料,你好像是 C # 。NET 开发人员。因此,我添加了对 Microsoft PEX 和鼹鼠项目的参考,它可以帮助您自动生成遗留代码的单元测试。我知道自动化生产不是最好的方式,但至少它是开始的方式。请查看 MSDN 杂志上关于使用 遗留代码的 PEX的这篇非常有趣的文章。

我建议阅读 TopTal 工程师写的一篇优秀的 文章文章,这篇文章解释了为什么 哪里要开始增加考试: 它包含了大量的数学知识,但其基本思想是:

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

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

您需要识别具有高 CA 和 CC 的类,即具有函数 F (CA,CC),并且在两个度量之间具有 最小的差异的类应该被赋予测试覆盖率的最高优先级。

为什么?因为一个高 CA 但是非常低 CC 类是非常重要的,但是不太可能突破。另一方面,低 CA 但高 CC 可能会破坏,但会造成较少的损害。所以你想要平衡。