【问题标题】:Rspec, Cucumber: best speed database clean strategyRspec,Cucumber:最佳速度数据库清理策略
【发布时间】:2011-03-21 13:54:02
【问题描述】:

我想提高我的测试速度。

  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 或 akephalos 时,将策略从 :transaction 即时更改为 :truncation 的最佳做法是什么?

附: Mysql、Rails 3、Rspec2、Cucumber

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

【问题讨论】:

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


【解决方案1】:

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

3. 是的,您应该在使用 database_cleaner gem 时关闭 use_transactional_fixtures,因为 gem 本身就支持事务。如果您只需要事务,那么只需使用_transactional_fixtures 并且永远不要加载 database_cleaner gem。

5. 以下代码将在:transaction:truncation 之间即时切换。 (用 rspec、capybara、rails3 对此进行了测试。)

功能这应该给你两全其美。 rack_test速度 当您不需要测试 javascript 的东西时,selenium灵活性 当您这样做时。

此代码还负责在需要时重新填充种子数据(此方法假定您使用 seed.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 或 cucumber。例如:

Rspec 示例:

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

黄瓜例子:

@javascript
Scenario: do something Ajaxy

【讨论】:

    【解决方案2】:

    使用事务性固定装置会更快,因为 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
    

    如果是我,我会将其分解为帮助程序,并将其作为每个示例组中需要关闭事务装置的单行宏调用。

    似乎确实应该有更好的方法,不过....祝你好运。

    【讨论】:

    • 这不涉及不能处理事务的 selenium 测试。有时你需要截断和trasaction。
    【解决方案3】:
    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's post 关于数据库清理器和 Rspec 的内容。代码的逐步分析在文章中。

    【讨论】:

    • 这是一个很棒的配置来平衡传统单元测试(应该使用 :transaction 因为它非常快)和集成测试(应该使用 :truncation 来支持多步骤/多页测试)
    【解决方案4】:

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

    【讨论】:

    • 是的,我用的是spork。但是题外话了。 Spork 节省约 15 秒。开始时。但是改变策略可以节省 10 分钟。对于我的测试套件...
    猜你喜欢
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2016-09-29
    • 1970-01-01
    • 2014-02-14
    • 2014-10-19
    相关资源
    最近更新 更多