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

发布于 2024-09-18 07:45:02 字数 357 浏览 4 评论 0原文

我的 RSpec 测试中有一个包含 2,000 多个示例的 Rails 应用程序。不用说,这是一个大型应用程序,有很多需要测试的地方。此时运行这些测试的效率非常低,而且由于需要很长时间,我们几乎不鼓励在推送新版本之前编写它们。我将 --profile 添加到我的 spec.opts 中以查找运行时间最长的示例,其中至少有 10 个示例平均需要 10 秒才能运行。这在 RSpec 专家中正常吗?对于一个例子来说 10 秒是不是太长了?我意识到,对于 2,000 个示例,彻底测试所有内容将花费相当长的时间 - 但在这一点上 4 小时有点可笑。

您看到运行时间最长的示例的时间是多少?我可以做些什么来对现有规格进行故障排除,以找出瓶颈并帮助加快速度。在这一点上,每一分钟都会很有帮助。

I have a Rails application with over 2,000 examples in my RSpec tests. Needless to say, it's a large application and there's a lot to be tested. Running these tests at this point is very inefficient and because it takes so long, we're almost at the point of being discouraged from writing them before pushing a new build. I added --profile to my spec.opts to find the longest running examples and there are at least 10 of them that take an average of 10 seconds to run. Is that normal amongst you RSpec experts? Is 10 seconds entirely too long for one example? I realize that with 2,000 examples, it will take a non-trivial amount of time to test everything thoroughly - but at this point 4 hours is a bit ludicrous.

What kind of times are you seeing for your longest running examples? What can I do to troubleshoot my existing specs in order to figure out bottlenecks and help speed things up. Every minute would really help at this point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

星星的轨迹 2024-09-25 07:45:02

对于任何单个测试的运行来说,10 秒都是很长的时间。我的直觉是您的规范目标同时运行单元测试和集成测试。这是项目遇到的典型问题,在某个阶段,如果您想更快地生产更多产品,您将需要克服这种技术债务。有许多策略可以帮助您做到这一点......我将推荐一些我过去使用过的策略。

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

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

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

哲学是,您希望常规构建快速 - 否则人们不会太乐意经常运行它们。所以回到那个领域。让您的常规测试快速运行,并使用持续集成服务器来运行更完整的构建。

集成测试是涉及外部依赖项(例如数据库、WebService、队列和有些人认为的文件系统)的测试。单元测试仅测试您想要检查的特定代码项。它应该运行得很快(45 秒内可以运行 9000 个),即大部分应该在内存中运行。

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

如果您的大部分单元测试小于集成测试套件,那么您就会遇到问题。这意味着不一致将开始更容易出现。因此,从这里开始,开始创建更多的单元测试来取代集成测试。在此过程中您可以做的事情有:

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

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

3.不要使用固定装置

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

4.添加检查以阻止单元测试变成集成测试

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

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

您还可以尝试结对和 TDD,这可以帮助您的团队编写更快的测试,因为:

  1. 有人在检查 - 所以没有人会偷懒
  2. 正确的 TDD 需要快速反馈。缓慢的测试只会让整个事情变得痛苦。

5.使用其他库来克服问题

有人提到了 spork(加快了 Rails3 下测试套件的加载时间)、Hydra/parallel_tests - 并行运行单元测试(跨多个核心)。

这可能应该最后使用。您真正的问题一直在步骤 1、2、3 中。解决了这个问题,您将能够更好地部署额外的基础设施。

10 seconds is a very long time for any single test to run. My gut feeling is that your spec target is running both unit and integration tests at the same time. This is a typical thing that projects fall into and at some stage, you will need to overcome this technical debt if you want to produce more, faster. There are a number of strategies which can help you to do this... and I'll recommend a few that I have used in the past.

1. Separate Unit From Integration Tests

The first thing I would do is to separate unit from integration tests. You can do this either by:

  1. Moving them (into separate folders under the spec directory) - and modifying the rake targets
  2. Tagging them (rspec allows you to tag your tests)

The philosophy goes, that you want your regular builds to be quick - otherwise people won't be too happy to run them often. So get back to that territory. Get your regular tests to run quick, and use a continuous integration server to run the more complete build.

An integration test is a test that involves external dependencies (e.g. Database, WebService, Queue, and some would argue FileSystem). A unit test just tests the specific item of code that you want checked. It should run fast (9000 in 45 secs is possible), i.e. most of it should run in memory.

2. Convert Integration Tests To Unit Tests

If the bulk of your unit tests is smaller than your integration test suite, you have a problem. What this means is that inconsistencies will begin to appear more easily. So from here, start creating more unit tests to replace integration tests. Things you can do to help in this process are:

  1. Use a mocking framework instead of the real resource. Rspec has an inbuilt mocking framework.
  2. Run rcov on your unit test suite. Use that to gauge how thorough your unit test suite is.

Once you have a proper unit test(s) to replace an integration test - remove the integration test. Duplicate testing only makes maintenance worse.

3. Don't Use Fixtures

Fixtures are evil. Use a factory instead (machinist or factorybot). These systems can build more adaptable graphs of data, and more importantly, they can build in-memory objects which you can use, rather than load things from an external data source.

4. Add Checks To Stop Unit Tests Becoming Integration Tests

Now that you have faster testing in place, time to put in checks to STOP this from occurring again.

There are libraries which monkey patch active record to throw an error when trying to access the database (UnitRecord).

You could also try pairing and TDD which can help force your team to write faster tests because:

  1. Somebody's checking - so nobody gets lazy
  2. Proper TDD requires fast feedback. Slow tests just make the whole thing painful.

5. Use Other Libraries To Overcome The Problem

Somebody mentioned spork (speeds up load times for the test suite under rails3), hydra/parallel_tests - to run unit tests in parallel (across multiple cores).

This should probably be used LAST. Your real problem is all the way in step 1, 2, 3. Solve that and you will be in a better position to role out additional infrastructure.

疏忽 2024-09-25 07:45:02

有关提高测试套件性能的精彩指南,请查看润滑您的套件 演示。

他记录了通过利用以下技术,测试套件运行时间提高了 45 倍:

For a great cookbook on improving the performance of your test suite, check out the Grease Your Suite presentation.

He documents a 45x speedup in test suite run time by utilizing techniques such as:

ペ泪落弦音 2024-09-25 07:45:02

你可以使用 Spork。它支持 2.3.x 、

https://github.com/sporkrb/spork

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

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

You can use Spork. It has support for 2.3.x ,

https://github.com/sporkrb/spork

or ./script/spec_server which may work for 2.x

Also you can edit the database configuration ( which essentially speeds up the database queries etc ), which will also increase performance for tests.

花开柳相依 2024-09-25 07:45:02

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

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

我赞同 Andrew Grimm 关于研究 CI 系统的评论,该系统可能允许您并行化测试套件。对于这么大的东西,这可能是唯一可行的解​​决方案。

10 seconds per example seems like a very long time. I've never seen a spec that took more than one second, and most take far less. Are you testing network connections? Database writes? Filesystem writes?

Use mocks and stubs as much as possible - they are much faster than writing code that hits the database. Unfortunately mocking and stubbing also take more time to write (and are harder to do correctly). You have to balance the time spent writing tests vs. the time spent running tests.

I second Andrew Grimm's comment about looking into a CI system which might allow you to parallelize your test suite. For something that size, it might be the only viable solution.

南巷近海 2024-09-25 07:45:02

如果您使用 ActiveRecord 模型,您还应该考虑 BCrypt 加密的成本。

您可以在此博客文章中阅读更多相关信息:http: //blog.syncopelabs.co.uk/2012/12/speed-up-rspec-test.html

If you are using ActiveRecord models, you should also consider the cost of BCrypt encryption.

You can read more about it on this blog post: http://blog.syncopelabs.co.uk/2012/12/speed-up-rspec-test.html

秋凉 2024-09-25 07:45:02

fast_require gem 可能会帮助你。
除此之外,你唯一的方法是(就像你所做的那样)分析和优化,或者使用 spork 或为你并行运行你的规范的东西。 http://ruby-toolbox.com/categories/distributed_testing.html

faster_require gem might help you.
Besides that your only way is to (like you did) profile and optimize, or use spork or something that runs your specs in parallel for you. http://ruby-toolbox.com/categories/distributed_testing.html

小耗子 2024-09-25 07:45:02

删除现有的测试套件。将非常有效。

Delete the existing test suite. Will be incredibly effective.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文