在大型Rails应用程序中加速RSpec测试


90

我的RSpec测试中有一个带有2000多个示例的Rails应用程序。不用说,这是一个很大的应用程序,还有很多需要测试的地方。此时运行这些测试的效率非常低,并且由于需要花费很长时间,因此在推动新版本之前,我们几乎不鼓励编写这些测试。我在自己的spec.opts文件中添加了--profile文件,以查找运行时间最长的示例,其中至少有10个示例平均需要运行10秒。在您的RSpec专家中这正常吗?10秒对于一个例子来说完全太长吗?我意识到,使用2,000个示例,将需要花费很短的时间来彻底测试所有内容-但此时4个小时有点荒谬。

您看到最长的运行示例是什么样的时间?我该怎么做才能解决现有规格问题,从而找出瓶颈并加快速度。在这一点上,每分钟确实会有所帮助。


1
慢速测试是集成测试吗?他们在打分贝吗?如果是这样,数据库多久重新加载一次,您可以模拟该数据库吗?
Kaleb Pederson

1
您是否能够运行与SeattleRB的自动测试类似的与您正在开发的零件有关的部分规格?您是否有可以运行所有测试的连续集成服务器?
安德鲁·格林

也要记住,所有事物都是相对的。我听说“ grrr,我们的测试套件将永远耗费20分钟”和16-20小时的时间。这一切都在情人眼中。给定测试10秒通常意味着单元测试已变成集成测试,如下所述。
Michael Durrant

对于此类问题的建议:perftools.rb与您的测试框架一起使用,以了解大部分时间在消耗什么。接听前10个电话,并尝试消除/略过。然后重复,直到高兴。
aledalgrande 2014年

Answers:


118

10秒对于任何单个测试来说都是很长的时间。我的直觉是您的规格目标同时运行单元测试和集成测试。这是项目陷入的典型情况,在某个阶段,如果您想更快地生产更多产品,就需要克服这一技术难题。有很多策略可以帮助您实现这一目标...并且我将推荐一些我过去使用过的策略。

1.将单元与集成测试分开

我要做的第一件事是将单元测试与集成测试分开。您可以通过以下方式进行此操作:

  1. 移动它们(到spec目录下的单独文件夹中)-并修改rake目标
  2. 标记它们(rspec允许您标记测试)

我们的理念是,您希望常规构建能够快速进行-否则人们不会太乐于经常运行它们。所以回到那个领域。使常规测试快速运行,并使用连续集成服务器运行更完整的版本。

集成测试是涉及外部依赖项(例如,数据库,WebService,Queue,有些会争辩FileSystem)的测试。单元测试仅测试要检查的特定代码项。它应该运行得很快(可能在45秒内达到9000),即大多数应在内存中运行。

2.将集成测试转换为单元测试

如果单元测试的大部分小于集成测试套件,则您有问题。这意味着不一致将更容易出现。因此,从这里开始创建更多的单元测试以替换集成测试。您可以在此过程中提供帮助的事情是:

  1. 使用模拟框架而不是实际资源。Rspec具有内置的模拟框架。
  2. 在单元测试套件上运行rcov。用它来衡量您的单元测试套件的彻底程度。

一旦您有适当的单元测试来替换集成测试,请删除集成测试。重复测试只会使维护工作更糟。

3.不要使用灯具

治具是邪恶的。请改用工厂(机械师或factorybot)。这些系统可以构建更具适应性的数据图,更重要的是,它们可以构建可使用的内存中对象,而不是从外部数据源中加载内容。

4.添加检查以停止单元测试成为集成测试

现在您已经有了更快的测试,是时候进行检查以阻止这种情况再次发生了。

有一些库,它们在尝试访问数据库(UnitRecord)时会猴子修补活动记录以引发错误。

您还可以尝试配对和TDD,这有助于迫使您的团队编写更快的测试,因为:

  1. 有人在检查-所以没人会偷懒
  2. 正确的TDD需要快速反馈。缓慢的测试只会使整个过程痛苦不堪。

5.使用其他图书馆来解决问题

有人提到spork(加快在rails3下测试套件的加载时间),hydra / parallel_tests-并行(跨多个内核)运行单元测试。

这可能应该在最后使用。您真正的问题一直在步骤1、2、3中解决。您将可以更好地发挥其他基础设施的作用。


好答案。的确,没有高级工具可以帮助快速运行不良测试。因此,请尝试只写好的。
Yura Omelchuk

5
对于您的第三点,我不同意您不应使用灯具。如果使用得当,它们将比工厂快,因为您不必创建对象。您的数据在那里,您不必为每个测试用例都创建它。
wallerjake 2014年

3
关于工厂更快的笑话是吧?
Mike Szyndel 2014年

加快测试通过选择性地避免工厂女孩- robots.thoughtbot.com/...
geekdev

16

有关改善测试套件性能的出色食谱,请查看“为套件润滑”演示。

他使用以下技术记录了测试套件运行时的45倍加速:


我喜欢链接,但不喜欢演示文稿。某人讲话的索引卡会提示说话者填写演示文稿的内容。
Brian Maltzan

此演示文稿不再显示。fast_context加快了多个Shoulda块的速度。quickerclip(该链接也无效)显然可以加快Paperclip的速度。Hydra不推荐使用parallel_tests和Gorgon。bootsnap进行了文件系统调整,现在包含在Rails中。Ruby的最新版本改进了分配和GC。
代表

5

您可以使用Spork。它支持2.3.x,

https://github.com/sporkrb/spork

或./script/spec_server可能适用于2.x

您还可以编辑数据库配置(从本质上加快数据库查询速度),这也将提高测试性能。


Spork很棒。它也可以在Rails 3上运行,但会有一些黑客攻击。但是,在Spork on Rails 3上要注意的一件事是它似乎并没有吸收控制器中的更改,因此您需要经常重新启动它。但是无论如何,Spork确实很棒,测试速度的提高非常重要。
关于Ruby 2010年

4
Spork仅用于加速启动,而不用于测试。因此,在很多规格的情况下,优势微不足道。
Reactormonk 2010年

与上述评论相反,按照railscast railscasts.com/episodes/285-spork的要求,spork可用于加快测试速度和启动速度。在非常大的应用程序上大大改进了我的rspec测试套件。(从192秒减少到10秒!)
jamesc

3

每个示例10秒似乎很长的时间。我从未见过花费超过一秒钟的规格,而大多数花费更少。您正在测试网络连接吗?数据库写?文件系统写?

尽可能使用模拟和存根-它们比编写命中数据库的代码快得多。不幸的是,模拟和存根也需要更多的时间来编写(并且很难正确地完成)。您必须平衡编写测试所花费的时间与运行测试所花费的时间。

对于安德鲁·格里姆Andrew Grimm)关于研究CI系统(可能允许您并行化测试套件)的评论,我是第二个评论。对于这么大的东西,它可能是唯一可行的解​​决方案。


是的,如果是10秒钟,我会分析它并查看瓶颈在哪里
rogerdpack

1
我有一个庞大的项目,并且运行单个rspec测试大约需要15-20秒。
ExiRe





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.