首页 文章

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

提问于
浏览
122

我正在考虑将单元测试添加到正在 生产环境 的现有项目中 . 它是在18个月之前开始的,之前我真的看到了TDD (face palm) 的任何好处,所以现在它是最模糊的想法从哪里开始添加单元测试 . 是什么让我觉得这是偶尔一个旧的bug似乎重新出现,或者一个错误被检查为固定而没有真正修复 . 单元测试可以减少或防止出现这些问题 .

通过阅读关于SO的similar问题,我've seen recommendations such as starting at the bug tracker and writing a test case for each bug to prevent regression. However, I' m关注我从开始使用TDD .

是否有任何流程/步骤应该遵守,以确保现有的解决方案是单元测试的,而不仅仅是提交?如何确保测试质量良好,并且不仅仅是测试的情况比没有测试更好 .

所以我猜我也要问的是;

  • 现有的 生产环境 解决方案是否值得努力?

  • 最好忽略对这个项目的测试,并将其添加到未来可能的重写中吗?

  • 什么会更有益;花几周时间添加测试或几周添加功能?

(显然,第三点的答案完全取决于您是否与管理层或开发人员交谈)


赏金原因

增加赏金以尝试吸引更广泛的答案,这不仅证实了我现有的怀疑,这是一件好事,而且还有一些很好的理由 .

我的目标是稍后用优点和缺点写出这个问题,试图向管理层表明,值得花费时间将产品的未来发展转移到TDD上 . 我想接受这个挑战,并在没有自己偏见的观点的情况下发展我的推理 .

23 回答

  • 1

    我建议由TopTal工程师阅读一篇精彩的article,解释 where 开始添加测试:它包含大量数学,但基本思路是:

    1)测量代码的 Afferent Coupling (CA) (其他类使用了多少类,意味着破坏它会造成广泛的破坏)

    2)测量你的代码的 Cyclomatic Complexity (CC) (更高的复杂性=更高的破坏变化)

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

    为什么?因为高CA但非常低的CC类非常重要但不太可能破坏 . 另一方面,低CA但高CC可能会破坏,但会造成较小的损害 . 所以你想要 balancer .

  • 4

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

    • 正如你所提到的,当你发现一个bug时,它是一个很好的alid测试 . 鉴于如此大部分的错误都是回归(50%?),几乎总是值得编写回归测试 .

    • 当您深入到代码区域进行修改时,现在是围绕它编写测试的好时机 . 根据代码的性质,不同的测试是合适的 . 一套很好的建议is found here .

    OTOH,不值得围绕编写人们满意的代码测试 - 特别是如果没有人要修改它 . 它只是没有增加 Value (除了可能理解系统的行为) .

    祝好运!

  • 1

    现有的 生产环境 解决方案是否值得努力?

    是!

    最好忽略对该项目的测试并将其添加到未来可能的重写中吗?

    没有!

    什么会更有益;花几周时间添加测试或几周添加功能?

    添加测试(尤其是自动化测试)使得项目将来更容易保持项目正常运行,并且使得向用户发送愚蠢问题的可能性大大降低 .

    先验的测试是检查您认为代码的公共接口(以及其中的每个模块)是否按照您的思维方式工作的测试 . 如果可以的话,尝试同时引入代码模块应该具有的每个隔离故障模式(请注意,这可能非常重要,您应该小心不要过于谨慎地检查事情是如何失败的,例如,您并不是真的想要做一些事情,比如计算失败时产生的日志消息的数量,因为验证它已被记录就足够了 .

    然后对您的错误数据库中的每个当前错误进行测试,该错误导致错误,并在错误修复时通过 . 然后修复那些错误! :-)

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

  • 3

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

    如果您编写的测试涵盖了您正在添加或修改的功能,您将立即获益 . 如果您等待重写,您可能永远不会进行自动化测试 .

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

  • 2

    我已经将单元测试引入了之前没有它的代码库 . 我参与的最后一个大项目,当我到达团队时,产品已经投入 生产环境 ,零单元测试 . 当我离开 - 2年后 - 我们进行了4500次左右的测试,在代码库中产生了大约33%的代码覆盖率,其中包含23万个 生产环境 LOC(实时财务Win-Forms应用程序) . 这可能听起来很低,但结果却是代码质量和缺陷率的显着提高 - 以及提高的士气和盈利能力 .

    如果您对相关各方有准确的理解和承诺,就可以完成 .

    首先,重要的是要了解单元测试本身就是一项技能 . 按照“常规”标准,您可以成为一个非常高效的程序员,并且仍然很难以在更大的项目中扩展的方式编写单元测试 .

    此外,特别针对您的情况,将单元测试添加到没有测试的现有代码库本身也是一项专业技能 . 除非您或团队中的某个人有成功将单元测试引入现有代码库的经验,否则我认为阅读Feather's book是一项要求(不是可选的或强烈推荐) .

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

    现在,您的意见和问题:

    但是,我担心我最终会错过大局并最终错过了如果我从开始使用TDD就会包含的基本测试 .

    简短的回答:是的,你会错过测试,是的,他们可能最初看起来不像他们在绿地情况下会有的 .

    更深层次的答案是这样的:没关系 . 你从没有测试开始 . 开始添加测试,并随时重构 . 随着技能水平的提高,开始提高添加到项目中的所有新编写代码的标准 . 不断改进......

    现在,在这两行之间进行阅读,我得到的印象是,这是“完美作为不采取行动的借口”的思维方式 . 更好的心态是专注于自信 . 因此,您可能还不知道该怎么做,您将弄清楚如何去填充空白 . 因此,没有理由担心 .

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

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

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

    是否有任何应遵循的流程/步骤,以确保现有解决方案经过适当的单元测试而不仅仅是装箱?

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

    培训你的员工 .

    从客户的角度出发,从某个地方开始并开始添加测试(见下文) .

    使用代码覆盖率作为您 生产环境 代码库的测试数量的指导参考 .

    构建时间应始终是快速的 . 如果您的构建时间很慢,那么您的单元测试技能就会滞后 . 找到慢速测试并改进它们(分离 生产环境 代码并单独测试) . 写得不错,你应该能够轻松地完成数以千计的单元测试,并且仍然可以在10分钟内完成构建(~1-ms ms / test是一个很好但非常粗略的指导原则,一些例外可能适用于使用反射等的代码) .

    检查和适应 .

    我如何确保测试质量良好,并且不仅仅是测试的情况比没有测试更好 .

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

    如果您没有这种经验或判断,请考虑与某人签约 .

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

    现有的 生产环境 解决方案是否值得努力?

    是 . 花在定制系统或解决方案上的绝大部分资金都用于 生产环境 之后 . 对质量,人员和技能的投资永远不会过时 .

    最好忽略对该项目的测试并将其添加到未来可能的重写中吗?

    您不仅要考虑对人员和技能的投资,还要考虑最重要的总体拥有成本和系统的预期使用寿命 .

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

    什么会更有益;花几周时间添加测试或几周添加功能?

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

    同样,它是对人员,技能和代码库质量的投资,因此需要时间 . 团队成员需要学习如何打破依赖关系,编写单元测试,学习新的习惯,提高纪律和质量意识,如何更好地设计软件等 . 重要的是要了解当你开始添加测试时,你的团队成员可能不会拥有这些技能尚未达到成功所需的水平,因此停止进度以花费所有时间来添加大量测试是行不通的 .

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

    第三,您希望在团队中灌输合理的业务重点值 . 质量永远不会以牺牲客户为代价,没有质量就无法快速前进 . 此外,客户生活在一个不断变化的世界中,您的工作就是让他更容易适应 . 客户一致性需要质量和业务 Value 流 .

    你正在做的是偿还技术债务 . 而您正在这样做,同时仍然为您的客户提供不断变化的需求 . 债务逐渐得到回报,情况有所改善,更容易为客户提供更好的服务并提供更多 Value . 等等 . 这种积极的动力是你应该瞄准的,因为它强调了可持续发展的原则,并将为你的开发团队,客户和利益相关者维护和改善道德 .

    希望有所帮助

  • 7

    是否值得将单元测试添加到正在 生产环境 的应用程序中取决于维护应用程序的成本 . 如果应用程序有很少的错误和增强请求,那么也许它不值得努力 . OTOH,如果应用程序有缺陷或频繁修改,那么单元测试将非常有益 .

    在这一点上,请记住我是一个新项目或重写(道歉,但这里是另一本书的链接,你真的应该阅读:Growing Object Oriented Software Guided by Tests

    我对第三个问题的回答与第一个问题的答案相同:它取决于项目的背景 .

    嵌入你的帖子是关于确保任何改装测试完成的另一个问题 properly . 要确保的重要一点是单元测试确实是 unit 测试,而这(通常不是)意味着改造测试需要重构现有代码以允许层/组件的分离(参见依赖注入;控制反转;存根;嘲讽) . 如果您未能强制执行此操作,那么您的测试将成为集成测试,这些测试非常有用,但与真正的单元测试相比,目标更少,更脆弱 .

  • 1

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

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

    • Black-box =在没有实施专业知识的情况下编写的测试,通常在边缘情况下进行调查,以确保事情像天真的用户所期望的那样发生 .

    • White-box =使用实施知识编写的测试,通常会尝试练习众所周知的失败点 .

    • Unit tests =各个单元的测试(功能,可分离的模块等) . 例如:确保数组类按预期工作,并且字符串比较函数返回各种输入的预期结果 .

    • Functional tests =同时测试整个系统 . 这些测试将同时运行系统的很大一部分 . 例如:init,打开连接,做一些真实的东西,关闭,终止 . 我喜欢区分这些和单元测试,因为它们有不同的用途 .

    当我在游戏后期将测试添加到运输产品时,我发现我从 white-boxfunctional 测试中获得了最大的收益 . 如果有's any part of the code that you know is especially fragile, write white-box tests to cover the problem cases to help make sure it doesn' t两次打破同样的方式 . 同样,整个系统的功能测试是一个有用的健全性检查,可以帮助您确保永远不会打破10个最常见的用例 .

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

    和其他人一样,我也会提醒你关于TDD的两个最重要的事情:

    • Creating tests is a continuous job. 它永远不会停止 . 每次编写新代码或修改现有代码时,都应尝试添加新测试 .

    • Your test suite is never infallible! 唐't let the fact that you have tests lull you into a false sense of security. Just because it passes the test suite doesn'吨意味着's working correctly, or that you haven'吨引入了微妙的表现回归等 .

  • -2

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

    如果已经存在的代码需要修改并且可以进行测试,那么这样做,但最好不要过于激烈地尝试为稳定的代码进行测试 . 这种事情往往会产生连锁效应,并且会失控 .

  • 1

    是 . 不 . 添加测试 .

    采用更多TDD方法实际上会更好地为您添加新功能和使回归测试变得更加容易 . 看看这个!

  • 2

    我不是一个经验丰富的TDD专家,但我当然会说尽可能多地进行单元测试非常重要 . 由于代码已经到位,我将首先获得某种单元测试自动化 . 我使用TeamCity来执行我的项目中的所有测试,并且它为您提供了组件如何执行的很好的总结 .

    有了这个,我就失败了 . 在我的情况下,有一些基本的三角函数问题需要解决各种输入,所以我测试了那些 . 我这样做的原因是,当我很容易浪费时间深入挖掘真正不需要触及的代码深度时,因为你知道它们已经过测试所有可能的输入(在我的情况下,那里是有限数量的输入) .

    好的,所以现在你希望对这些关键部分感觉更好 . 而不是坐下来敲打所有的测试,我会在它们出现时攻击它们 . 如果您遇到了一个真正的PITA修复错误,请为其编写单元测试并将其排除在外 .

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

    从那里,我将获得您的构建服务器或您使用代码覆盖工具配置的任何自动化 . 它们会创建令人讨厌的条形图,其中包含较大的红色区域,而您的覆盖范现在100%的覆盖率不是你的目标,100%的覆盖率也不一定意味着你的代码是防弹的,但是当我有空闲时间时,红色条形肯定会激励我 . :)

  • 23

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

    然后我会针对新发现的错误进行缺陷驱动开发,编写单元测试以重现问题,并在测试通过之前处理错误 .

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

    我不是这个过程的专家,但是从我的经验来看,我可以告诉你BDD通过自动UI测试并不容易,但我认为这是值得的,并且可能会在你的情况下产生最大的好处 .

  • 2

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

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

    • 每个测试套件首先将数据库初始化为已知状态 . 我们实际上有几十个我们保留在Subversion中的回归数据集(由于其庞大的规模,在我们代码的单独存储库中) . 每个测试的FixtureSetUp将这些回归数据集中的一个复制到临时数据库中,然后从那里运行 .

    • 测试夹具设置然后运行一些我们感兴趣的结果的过程 . (这一步是可选的 - 一些回归测试仅用于测试报告 . )

    • 然后,每个测试运行一个报告,将报告输出到.csv文件,并将该.csv的内容与保存的快照进行比较 . 这些快照.csvs存储在每个回归数据集旁边的Subversion中 . 如果报告输出与保存的快照不匹配,则测试失败 .

    回归测试的目的是告诉您是否有变化 . 这意味着如果你破坏了它们就会失败,但是如果你故意改变了某些东西它们也会失败(在这种情况下修复是更新快照文件) . 您不知道快照文件是否正确 - 系统中可能存在错误(然后当您修复这些错误时,回归测试将失败) .

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

    然后,当我们修复错误,添加增强功能或需要理解某些代码时,我们回去开始添加单元测试 . 回归测试绝不会消除单元测试的需要;它们只是一级安全网,因此您可以快速获得一定程度的测试覆盖率 . 然后你可以开始重构来破坏依赖关系,所以你可以添加单元测试;并且回归测试可以让您确信您的重构不会破坏任何内容 .

    回归测试存在问题:它们很慢,并且有太多原因可以解决它们 . 但至少对我们来说,它们非常值得 . 他们've caught countless bugs over the last five years, and they catch them within a few hours, rather than waiting for a QA cycle. We still have those original regression tests, spread over seven different continuous-build machines (separate from the one that runs the fast unit tests), and we even add to them from time to time, because we still have so much code that our 6,000+ unit tests don'覆盖 .

  • 10

    Update

    原答案6年后,我的表现略有不同 .

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

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

    Earlier answer

    我要在这里引起一些眉毛:)

    首先,你的项目是什么 - 如果它是一个编译器或语言或框架或其他任何不会在很长一段时间内发生功能改变的东西,那么我认为添加单元测试真是太棒了 .

    但是,如果您正在处理可能需要更改功能的应用程序(因为需求更改),那么就没有必要花费额外的精力 .

    为什么?

    • 单元测试仅涵盖代码测试 - 代码是否符合其设计目标 - 它不能替代手动测试,无论如何必须完成(发现功能性错误,可用性问题和所有其他类型的问题)

    • 单位测试花费时间!现在我来自哪里,这是一种宝贵的商品 - 而且企业通常会在完整的测试套件中选择更好的功能 .

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

    • 单元测试不会影响产品的感知质量 - 用户看到的质量 . 当然,您的方法可能与第1天完全一样,表示层和业务层之间的界面可能是原始的 - 但猜猜是什么?用户不在乎!找一些真正的测试人员来测试你的应用程序 . 通常情况下,这些方法和界面迟早会发生变化 .

    什么会更有益;花几周时间添加测试或几周添加功能? - 除了编写测试之外,还有很多东西可以做得更好 - 编写新功能,提高性能,提高可用性,编写更好的帮助手册,解决待处理的错误等等 .

    现在不要误解我的意思 - 如果你对未来100年的事情不会发生变化表示绝对肯定,请继续前进,将自己敲开并编写测试 . 自动化测试也是API的一个好主意,您绝对不想破坏第三方代码 . 在其他任何地方,它只是让我以后出货的东西!

  • 15

    我同意大多数人所说的话 . 向现有代码添加测试很有 Value . 我永远不会不同意这一点,但我想补充一点 .

    尽管在现有代码中添加测试很有 Value ,但确实需要付出代价 . 它的代价是不构建新功能 . 这两个方面如何 balancer 完全取决于项目,并且有许多变量 .

    • 将所有代码置于测试状态需要多长时间?天?周?月?年份?

    • 你在为谁编写这段代码?支付客户?一位教授?一个开源项目?

    • 你的日程安排是什么样的?你必须遇到艰难的最后期限吗?你有截止日期吗?

    再说一遍,让我强调一下,测试很有 Value ,你应该努力测试你的旧代码 . 这实际上更多的是你如何处理它 . 如果您能够放弃所有内容并将所有旧代码置于测试之下,那就去做吧 . 如果's not realistic, here' s你应该做什么 at the very least

    • 您编写的任何新代码都应完全在单元测试中

    • 您碰巧触摸的任何旧代码(错误修复,扩展等)都应置于单元测试之下

    而且,这不是一个全有或全无的命题 . 如果您有一个由四人组成的团队,并且您可以通过将一两个人放在传统测试任务上来满足您的最后期限,那么一定要这样做 .

    Edit:

    我的目标是稍后用优点和缺点写出这个问题,试图向管理层表明,值得花费时间将产品的未来发展转移到TDD上 .

    这就像问“使用源代码控制有什么优缺点?”或“在雇用人员之前采访人们有哪些利弊?”或“呼吸的利弊是什么?”

    Sometimes there is only one side to the argument. 您需要为任何复杂的项目进行某种形式的自动化测试 . 不,测试不会自己写,而且,是的,需要一点额外的时间才能把事情搞定 . 但 in the long run it will take more time and cost more money to fix bugs after the fact than write tests up front. 期间 . 这里的所有都是它的 .

  • 1
    • 是的,确实如此 . 当您开始添加新功能时,它可能会导致一些旧的代码修改,并且作为结果,它是潜在错误的来源 .
      在开始添加新功能之前

    • (参见第一个)所有(或几乎)代码(理想情况下)应该由单元测试覆盖 .

    • (见第一个和第二个):) . 一个新的宏伟功能可以"destroy"旧的工作代码 .

  • 1

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

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

    • 产品建议 - 我以前使用免费的网络产品Junit Factory,但遗憾的是它现在关闭了 . 然而,该产品仍然存在于商业许可的AgitarOne JUnit Generator中http://www.agitar.com/solutions/products/automated_junit_generation.html

    • 对于您修复的每个错误或从现在开始添加的功能,使用TDD方法确保新代码可以测试并将这些测试放在普通的测试源树中 .

    • 现有代码也可能需要更改或重构,以便在添加新功能时使其可测试;您的烟雾测试将为您提供一个安全网,以抵御回归或无意中微妙的行为变化 .

    • 通过TDD进行更改(错误修复或功能)时,如果完成,则伴随冒烟测试可能会失败 . 由于所做的更改,验证故障是否符合预期,并删除不太可读的烟雾测试,因为您的手写单元测试完全覆盖了该改进的组件 . 确保您的测试覆盖率不会下降,只保持不变或增加 .

    • 修复错误时,编写一个首先暴露错误的失败单元测试 .

  • 2

    改装单元测试的问题是你会意识到你没有考虑在这里注入依赖或在那里使用接口,不久之后你将重写整个组件 . 如果你有时间这样做,你将 Build 一个很好的安全网,但你可能会在路上引入微妙的错误 .

    我参与了很多项目,从第一天起就真正需要进行单元测试,并且没有简单的方法可以将它们放在那里,而不是完全重写,当代码工作并且已经赚钱时,这通常是不合理的 . 最近,我已经开始编写powershell脚本,以一种方式运行代码,一旦它被引发就会重现缺陷,然后将这些脚本保存为一套回归测试进一步的变化 . 这样你至少可以开始为应用程序构建一些测试而不会过多地改变它,但是,这些更像是端到端的回归测试而不是正确的单元测试 .

  • 4

    你说你working effectively with legacy code上的文章 . 然后买书:)

  • 0

    我想通过说单元测试非常重要来开始这个答案,因为它可以帮助你在蠕虫进入 生产环境 之前阻止它们 .

    Identify the areas projects/modules where bugs have been re-introduced. start with those projects to write tests. 为新功能和错误修复编写测试是完全有意义的 .

    现有的 生产环境 解决方案是否值得努力?

    是 . 您将看到错误的影响,维护变得更容易

    最好忽略对该项目的测试并将其添加到未来可能的重写中吗?

    我建议从现在开始 .

    什么会更有益;花几周时间添加测试或几周添加功能?

    你问的是错误的问题 . 当然,功能比其他任何东西都重要 . 但是,你应该问一下,花几周时间添加测试会让我的系统更稳定 . 这有助于我的最终用户吗?它是否有助于团队中的新开发人员理解项目,并确保他/她不会因为缺乏对变更整体影响的理解而引入错误 .

  • 155

    有很多好的答案所以我不会重复他们的内容 . 我检查了你的 Profiles ,看来你是C#.NET开发人员 . 因此,我正在添加对Microsoft PEX and Moles项目的引用,该项目可以帮助您自动生成遗留代码的单元测试 . 我知道自动生成不是最好的方法,但至少它是开始的方式 . 查看MSDN杂志上关于使用PEX for legacy code这篇非常有趣的文章 .

  • 3

    这取决于...
    它是's great to have unit tests but you need to consider who your users are and what they are willing to tolerate in order to get a more bug-free product. Inevitably by refactoring your code which has no unit tests at present, you will introduce bugs and many users will find it hard to understand that you are making the product temporarily more defective to make it less defective in the long run. Ultimately it'的用户谁拥有最后的发言权......

  • 6

    我非常喜欢Refactor the Low-hanging Fruit作为解决从哪里开始重构的问题的答案 . 这是一种轻松进入更好设计的方法,而不会比你咀嚼更多 .

    我认为同样的逻辑适用于TDD - 或者仅仅是单元测试:根据需要编写您需要的测试;为新代码编写测试;在出现错误时编写测试 . 您担心忽略代码库中难以触及的区域,这肯定是一种风险,但作为一种入门方式:开始吧!您可以使用代码覆盖工具降低风险,并且风险不是(在我看来)那么大,无论如何:如果您正在覆盖错误,覆盖新代码,覆盖您正在查看的代码,那么你将覆盖最需要测试的代码 .

  • 5

    现有的 生产环境 解决方案是否值得努力?
    是 . 但是您不必编写所有单元测试即可开始使用 . 只需逐个添加它们 .

    最好忽略对该项目的测试并将其添加到未来可能的重写中吗?
    不会 . 第一次添加破坏功能的代码时,您会后悔的 .

    什么会更有益;花几周时间添加测试或几周添加功能?
    对于新功能(代码),它很简单 . 首先编写单元测试,然后编写功能 . 对于旧代码,您决定在路上 . 你没有必要进行所有的单元测试......添加那些最不受伤害的单元测试...时间(和错误)将告诉你必须关注哪一个;)

相关问题