Rspec、Cucumber:最佳速度数据库清理策略

发布于 2024-10-25 00:39:03 字数 800 浏览 1 评论 0原文

我想提高测试速度。

  1. 我应该使用 use_transactional_fixtures 还是使用 database_cleaner gem?
  2. 哪种database_cleaner策略是最好的?我注意到,从 :truncation 迁移到 :transaction 后,我的 800 多个示例的运行速度提高了约 4 倍!
  3. 使用database_cleaner :transaction 时是否应该关闭use_transactional_fixtures
  4. rack_test 的最佳策略真的是 :transaction 吗?
  5. 使用 selenium 或

PS Mysql、Rails 3、Rspec2、Cucumber

PPS 我了解 sporkparallel_test 并使用它们。但它们是题外话。例如,Spork 在整个套件运行中节省了大约 15-20 秒,但从 :transaction 更改为 :truncation 大大增加了运行时间,从 3.5 分钟增加到 13.5 分钟(相差 10 分钟) )。

I would like to increase the speed of my tests.

  1. Should I use use_transactional_fixtures or go with the database_cleaner gem?
  2. 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!
  3. Should I turn off use_transactional_fixtures when I use database_cleaner :transaction?
  4. Is it true that the best strategy for rack_test is :transaction?
  5. 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 技术交流群。

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

发布评论

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

评论(4

伏妖词 2024-11-01 00:39:03

使用事务性固定装置会更快,因为 DBMS 不会提交更改(因此不会发生大量 IO 来重置测试之间的数据库),但正如您所知,这并不总是有效。

我们在测试环境中使用 SQLite 内存数据库取得了一些成功,因此测试运行速度非常快,同时关闭了事务固定装置。此选项也适用于 MySQL(使用 :options 来设置“ENGINE=MEMORY”),但我个人从未这样做过,如果您搜索,您会发现一些有关涉及警告的线程。可能值得一看。不过,根据您的测试方法,使用不同的数据库引擎可能是不可接受的。

我建议您启用事务固定装置并使用 DatabaseCleaner gem 有选择地禁用每个示例组的事务固定装置。我不能说我已经尝试过这个,但由于您没有任何答案,我认为任何事情都可能对您有所帮助。

before(:all) do
  DatabaseCleaner.strategy = :transaction
  DatabaseCleaner.clean_with(:truncation)
end

before(:each) do
  DatabaseCleaner.start
end

after(:each) do
  DatabaseCleaner.clean
end

如果是我,我会将其分解为一个助手,并将其称为每个需要关闭事务装置的示例组中的单行宏。

看来确实应该有更好的方法,不过……祝你好运。

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.

before(:all) do
  DatabaseCleaner.strategy = :transaction
  DatabaseCleaner.clean_with(:truncation)
end

before(:each) do
  DatabaseCleaner.start
end

after(:each) do
  DatabaseCleaner.clean
end

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.

审判长 2024-11-01 00:39:03

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.

config.use_transactional_fixtures = false
RSpec.configure do |config|
  config.before(:suite) do
    require "#{Rails.root}/db/seeds.rb"
  end

  config.before :each do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.strategy = :transaction
    else
      DatabaseCleaner.strategy = :truncation
    end
    DatabaseCleaner.start
  end
  config.after(:each) do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.clean
    else
      DatabaseCleaner.clean
      load "#{Rails.root}/db/seeds.rb"
    end
  end
end

感谢 Jo Liss 的指点道路。

PS:如何动态切换驱动程序

上述解决方案假设您已经知道如何动态切换驱动程序。如果有些人不这样做,

请执行以下操作:如上所述,我们假设您通常会使用默认的水豚驱动程序rack_test,但需要使用selenium 来测试一些Ajaxy 内容。当您想使用 selenium 驱动程序时,请使用 :js =>; true@javascript 分别表示 Rspec 或 cucumber。例如:

Rspec 示例:

describe "something Ajaxy", :js => true do

黄瓜示例:

@javascript
Scenario: do something Ajaxy

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 of selenium 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.

config.use_transactional_fixtures = false
RSpec.configure do |config|
  config.before(:suite) do
    require "#{Rails.root}/db/seeds.rb"
  end

  config.before :each do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.strategy = :transaction
    else
      DatabaseCleaner.strategy = :truncation
    end
    DatabaseCleaner.start
  end
  config.after(:each) do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.clean
    else
      DatabaseCleaner.clean
      load "#{Rails.root}/db/seeds.rb"
    end
  end
end

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:

describe "something Ajaxy", :js => true do

Cucumber example:

@javascript
Scenario: do something Ajaxy
何时共饮酒 2024-11-01 00:39:03
RSpec.configure do |config|

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end

这是来自 Avdi Grimm 的帖子 关于数据库清理器和 Rspec。文章中对代码进行了逐步分析。

RSpec.configure do |config|

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end

This is from Avdi Grimm's post about database cleaner and Rspec. Step-by-step analysis of the code is in the article.

故事↓在人 2024-11-01 00:39:03

你用过 Spork 吗?它大大提高了速度。

Have you used Spork ? It greatly enhances speed.

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