Rspec,Cucumber:最佳速度数据库清洁策略

时间:2011-03-21 13:54:02

标签: ruby-on-rails database rspec performance cucumber

我想提高测试速度。

  1. 我应该使用use_transactional_fixtures还是使用database_cleaner gem?
  2. 哪种database_cleaner策略最好?我注意到从:truncation迁移到:transaction后,我的800多个示例的运行速度提高了大约4倍!
  3. 当我使用database_cleaner use_transactional_fixtures时,我应该关闭:transaction吗?
  4. rack_test的最佳策略是:transaction
  5. 是真的吗?
  6. 使用selenium或akephalos时,从:transaction:truncation动态更改策略的最佳做法是什么?
  7. P.S。 Mysql,Rails 3,Rspec2,Cucumber

    P.P.S。我了解sporkparallel_test并使用它们。但他们是偏离主义的。例如,Spork在整个套件运行中节省大约15-20秒,但从:transaction更改为:truncation会大大增加运行时间3.5到13.5分钟(差异10分钟)。

4 个答案:

答案 0 :(得分:6)

1。,2。& 4。,如果您使用的是capybara的默认引擎rack_test,您应该使用事务(使用use_transactional_fixtures或来自database_cleaner gem的事务支持)。如您所述,使用事务比使用截断策略要快得多。但是,当数据库写入可以通过不同的线程(与selenium一样)时,事务将不起作用。因此,您需要使用截断(或强制所有内容通过一个数据库线程 - 另一个选项)。

3。是的,您应该在使用database_cleaner gem时关闭use_transactional_fixtures,因为gem本身支持事务。如果您只需要事务,那么只需使用use_transaction_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:如何动态切换驱动程序

上述解决方案假设您已经知道如何动态切换驱动程序。如果有人来这里不这样做,请按照以下方式进行:

如上所述,我们假设您通常会使用默认的capybara驱动程序rack_test,但需要使用selenium来测试一些Ajaxy的东西。当您想使用selenium驱动程序时,分别使用:js => true@javascript代替Rspec或黄瓜。例如:

Rspec示例:

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

黄瓜的例子:

@javascript
Scenario: do something Ajaxy

答案 1 :(得分:5)

使用事务性夹具会更快,因为DBMS不提交更改(因此在测试之间重置数据库时不会发生大量IO)但是您知道并不总是有效。

我们在测试环境中使用SQLite内存数据库取得了一些成功,因此测试运行得非常快,同时关闭了事务夹具。这个选项也适用于MySQL(使用:选项来设置“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

如果是我,我会把它当作一个帮助器,并将其称为每个示例组中的一行宏,需要关闭事务处理器。

似乎确实应该有一个更好的方法,但是......祝你好运。

答案 2 :(得分:1)

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

这是关于数据库清理工具和Rspec的Avdi Grimm's post。文章中逐步分析了代码。

答案 3 :(得分:-1)

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