Rspec、Cucumber:最佳速度数据库清理策略
我想提高测试速度。
- 我应该使用
use_transactional_fixtures
还是使用database_cleaner
gem? - 哪种database_cleaner策略是最好的?我注意到,从
:truncation
迁移到:transaction
后,我的 800 多个示例的运行速度提高了约 4 倍! - 使用database_cleaner
:transaction
时是否应该关闭use_transactional_fixtures
? - rack_test 的最佳策略真的是
:transaction
吗? - 使用 selenium 或
PS Mysql、Rails 3、Rspec2、Cucumber
PPS 我了解 spork 和 parallel_test 并使用它们。但它们是题外话。例如,Spork 在整个套件运行中节省了大约 15-20 秒,但从 :transaction
更改为 :truncation
大大增加了运行时间,从 3.5 分钟增加到 13.5 分钟(相差 10 分钟) )。
I would like to increase the speed of my tests.
- Should I use
use_transactional_fixtures
or go with thedatabase_cleaner
gem? - Which database_cleaner strategy is the best? I noticed that after migration from
:truncation
to:transaction
my more than 800 examples run about 4 times faster! - Should I turn off
use_transactional_fixtures
when I use database_cleaner:transaction
? - Is it true that the best strategy for rack_test is
:transaction
? - What is the best practices for changing strategy on the fly from
:transaction
to:truncation
when using selenium or akephalos?
P.S. Mysql, Rails 3, Rspec2, Cucumber
P.P.S. I know about spork and parallel_test and using them. But they are offtopic. For example, Spork save about 15-20 sec on whole suite run, but changing from :transaction
to :truncation
dramatically increase running time from 3.5 to 13.5 minutes (10 minutes difference).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用事务性固定装置会更快,因为 DBMS 不会提交更改(因此不会发生大量 IO 来重置测试之间的数据库),但正如您所知,这并不总是有效。
我们在测试环境中使用 SQLite 内存数据库取得了一些成功,因此测试运行速度非常快,同时关闭了事务固定装置。此选项也适用于 MySQL(使用 :options 来设置“ENGINE=MEMORY”),但我个人从未这样做过,如果您搜索,您会发现一些有关涉及警告的线程。可能值得一看。不过,根据您的测试方法,使用不同的数据库引擎可能是不可接受的。
我建议您启用事务固定装置并使用 DatabaseCleaner gem 有选择地禁用每个示例组的事务固定装置。我不能说我已经尝试过这个,但由于您没有任何答案,我认为任何事情都可能对您有所帮助。
如果是我,我会将其分解为一个助手,并将其称为每个需要关闭事务装置的示例组中的单行宏。
看来确实应该有更好的方法,不过……祝你好运。
Using transactional fixtures will be faster since the DBMS doesn't commit changes (and therefore no heavy IO occurs resetting the database between tests) but as you know won't always work.
We have had some success using SQLite in-memory databases in the test environment so tests run super fast while leaving transactional fixtures off. This option is also available for MySQL (use :options to set "ENGINE=MEMORY") but I've never done it personally and if you search you'll find a few threads about caveats involved. Might be worth a look. Depending on your testing methodology it may not be acceptable to use a different DB engine though.
I suggest you enable transactional fixtures and use the DatabaseCleaner gem to selectively disable transactional fixtures per example group. I can't say that I've tried this but since you didn't have any answers I figured anything might potentially help you out.
If it were me I'd factor this out into a helper and call it as a one-line macro from each example group that needs transactional fixtures turned off.
Seems like there really should be a better way, though.... best of luck.
1., 2. & 4.,如果您使用水豚的默认引擎rack_test,则应该使用事务(使用
use_transactional_fixtures
或database_cleaner gem的事务支持)。正如您所指出的,使用事务比使用截断策略要快得多。然而,当数据库写入可以通过不同的线程(如硒)时,事务将不起作用。因此,您需要使用截断(或强制所有内容都经过一个数据库线程——另一种选择)。3. 是的,在使用database_cleaner gem 时,您应该关闭
use_transactional_fixtures
,因为gem 本身就支持事务。如果您只需要事务,那么只需使用_transactional_fixtures,并且永远不要加载database_cleaner gem。5. 以下代码将在
:transaction
和:truncation
之间动态切换。 (使用 rspec、capybara、rails3 对此进行了测试。)功能 这应该为您提供两全其美的功能。当您不需要测试 JavaScript 内容时,
rack_test
的速度和当您需要测试时selenium
的灵活性 。此外,此代码还负责在需要时重新填充种子数据(此方法假设您使用 seeds.rb 来加载种子数据 - 正如当前约定)。
将以下代码添加到spec_helper.
感谢 Jo Liss 的指点道路。
PS:如何动态切换驱动程序
上述解决方案假设您已经知道如何动态切换驱动程序。如果有些人不这样做,
请执行以下操作:如上所述,我们假设您通常会使用默认的水豚驱动程序rack_test,但需要使用selenium 来测试一些Ajaxy 内容。当您想使用 selenium 驱动程序时,请使用
:js =>; true
或@javascript
分别表示 Rspec 或 cucumber。例如:Rspec 示例:
黄瓜示例:
1., 2. & 4., You should use transactions (either with
use_transactional_fixtures
or transactions support from the database_cleaner gem) if you are using capybara's default engine, rack_test. As you noted, using transactions are substantially faster than using a truncation strategy. However, when database writes can go through different threads (as with selenium) transactions won't work. So you'll need to use truncation (or force everything to go through one db thread--another option).3. Yes, you should turn off
use_transactional_fixtures
when using the database_cleaner gem since the gem natively support transactions. If you only need transactions then just use_transactional_fixtures and never load the database_cleaner gem.5. The following code will switch between
:transaction
and:truncation
on the fly. (Tested this with rspec, capybara, rails3.)Features This should give you the best of both worlds. The speed of
rack_test
when you don't need to test javascript stuff and the flexibility ofselenium
when you do.Also this code takes care of repopulating seed data in cases where it is needed (this method assumes you use seeds.rb to load your seed data--as is the current convention).
Add the following code to spec_helper.
Thanks Jo Liss for pointing the way.
PS: How to switch drivers on the fly
The above solution assumes you already know how to switch drivers on the fly. In case some who come here don't, here's how:
As above let's assume that you normally will use the default capybara driver rack_test, but need to use selenium to test some Ajaxy stuff. When you want to use the selenium driver use
:js => true
or@javascript
for Rspec or cucumber respectively. For example:Rspec example:
Cucumber example:
这是来自 Avdi Grimm 的帖子 关于数据库清理器和 Rspec。文章中对代码进行了逐步分析。
This is from Avdi Grimm's post about database cleaner and Rspec. Step-by-step analysis of the code is in the article.
你用过 Spork 吗?它大大提高了速度。
Have you used Spork ? It greatly enhances speed.