【问题标题】:How to deal with slow unit tests while doing TDD in large c# project如何在大型 c# 项目中进行 TDD 时处理缓慢的单元测试
【发布时间】:2018-12-04 18:30:30
【问题描述】:

使用 Visual Studio 2017 NUnit 和 resharper 测试运行器,在大型 c# 项目(5000+)测试中进行 TDD 时如何保持良好的单元测试速度。即使每个测试只需要 5 毫秒,也就是 25 秒,这对于一个 TDD 周期来说是相当慢的。

我们的测试不调用数据库,也不调用外部 Web 服务。他们只测试业务逻辑。

我发现使用最小起订量,单独执行 Mock.Setup() 几乎需要 1 毫秒。由于每个测试我们可能有一些最小起订量设置调用,这是我们缓慢的单元测试的主要罪魁祸首。

有什么方法可以加快单元测试的速度吗?有没有比 moq 更快的模拟库?或者也许是另一个更快的测试运行器?

【问题讨论】:

  • 25s 进行 5000 次测试是相当合理的,无论如何在我看来。一种方法是将您的解决方案分解,也许将通用/基础设施的东西放入可重用的 NuGet 包中。这样总的单元测试时间不会减少,但开发人员通常会一次处理一个组件。
  • 我会先说我从未做过 TDD,但我经常进行单元测试。在我的阅读中,我总是从“测试应该快速运行”中得到的印象是,测试不应该花费几个小时,甚至几分钟来运行。长时间运行的测试鼓励不运行测试。等待 25 秒并不长,IMO。
  • 您使用的是哪个测试框架?有些支持并行运行测试。
  • 这是个好主意,我正在使用 Nunit,它确实支持并行测试,我会尝试一下,谢谢!
  • 大多数 NUnit 运行程序还支持仅运行受影响的测试,因此每次更改都不应该在 5000 附近运行。 NCrunch 是 TDD 的一个非常棒的工具,特别是对于较小的解决方案,因为它根据测试结果在您​​键入时实时注释您的代码。不过不是免费的。

标签: c# visual-studio unit-testing tdd resharper


【解决方案1】:

你走错了路:所有单元测试的整体运行时间仍然在一个非常合理的范围内!

在进行开发(可能使用 TDD)时,您并不关心 所有 单元测试。您只关心与当前组件/包/...相关的那些!

如:当您在文件 A 中进行更改时,您可能希望(手动)运行目录 A 的所有单元测试。您进行另一个小的更改,再次运行这些测试。

然后,稍后,当您认为:“我现在完成了”时,然后您调用所有单元测试,以确保您没有破坏建筑物另一端的某些东西重新整理那边那个房间的家具。

所以,答案是:你很好,别担心。

我们有 5000 多个 Java 单元测试。在我们最快的构建服务器上,大约需要 10 分钟才能完成所有工作。但这仍然可以。后端构建在 20 分钟后仍然返回并告诉我们“损坏”或“一切正常”。为什么?因为只有当我决定我的更改集完成时,构建服务器才会启动,并将它推送到服务器。

如果这 25 秒是个问题,那是因为您过于频繁地运行所有测试,因为您手动触发了它们。现在:宁愿花精力寻找聪明的方法,只在以有效方式处理特定问题时运行相关测试。 (在带有 JUnit 的 Java 中,这很简单:我点击当前包,然后转到“在此处运行所有测试)

【讨论】:

  • 如果您使用的是带有 Visual Studio 的企业 SKU,那么要仅测试您正在处理的内容,您可以为您正在工作的代码区域启用 Live Unit Testing 功能。 NCrunch(如上面的 cmets 所述)是另一个类似的工具。
【解决方案2】:

考虑摆脱您拥有的大多数测试。

虽然我在单元测试和 TDD 方面没有太多经验,但我拥有的有限经验表明大多数单元测试毫无用处。并且有经验丰富的人支持我的观点,作为这个观点的一个例子,考虑以下两篇文章:

我不确定这个讨论的连续性(即谁是第一个提出这个问题的人),但是这里有几个人参考了上面的文章并同意它,并且可能会添加一些他们自己的观点:

请注意,争论根本不是关于测试,而是关于广泛的单元测试,而不是集成和系统级测试。

【讨论】:

  • 第一篇文章争议很大。有人可能会争辩说,编写某些类型的单元测试的成本超过了收益,但你的开场白过于宽泛而无法正确。
  • @Stijn 当然这是有争议的,如果这个想法被广泛承认为真理,那么每个人都会遵循它。此外,没有一篇文章主张禁止单元测试,只需停止编写数千个单元测试,将重点放在集成和系统测试上。
  • 通过集成测试和系统测试,您会看到 IF 您的代码是否正常工作,但要找出 哪里 代码错误是非常困难的.单元测试非常具体地告诉您什么不起作用,它回答了 where 部分。所以你需要两者,然后@ghostcat 的答案是一个很好的答案。只测试您需要的东西,但保留所有这些,它们就是您的回归套件。
  • @TerjeSandstrøm 不是真的。 “干净”的单元测试模拟了依赖关系,因此如果 A 类与特定参数一起正常工作,而 B 类与特定参数一起正常工作并不意味着它们相交的地方也可以与这些相同的参数一起正常工作。单元测试不会通过设计捕获错误 - A 类测试中没有 B 类,B 类测试中没有 A 类,只有模拟
  • “干净”的单元测试不一定要模拟依赖项。请参阅 TDD 的 Classic vs Mockist 方法。对此有很多争论。
猜你喜欢
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多