DatabaseCleanerのstrategyを動的に切替える

Capybaraのdriverの切り替えに合わせて、database_cleanerのstrategyを動的に切替える

環境

  • rails (4.2.1)
  • capybara (2.4.4)
  • database_cleaner (1.4.1)

やりたいこと

  • Capybaraでpoltergeistなどのjsdriverを利用しつつも、テストの実行速度をできるだけあげたい

Capybaraでjsを含む画面をテストしようとしてぶつかる問題

  • Capybaraでpoltergeistなどのjsdriverを利用する場合、rspecとは別のサーバプロセスが起動してテストが実行されます。

  • specのletやbeforeで設定したテストデータはrspecのプロセスでセットアップされるため、テストやDBクリアの戦略をtransactionにしていると、jsdriverからテストデータが見えない。
    (transactionにしているとテスト実行後にrollbackされる(commitされない)ため別プロセスからはデータが見えない。)

  • そのため、jsdriverを使用するテストではDBクリアの戦略をtruncationにする必要があります。こうするとテストデータのセットアップではcommitして、テスト実行後にtruncationが行われDBがクリアされるので、別のプロセスからテストデータが見えるようになります。(connectionをshareするやり方もあるみたいです。)

  • しかし、DBのクリアをtruncationで行うとtransactionより実行コストがかかるため、jsdriverを使用しないテストでもtruncationを利用するとテスト全体が遅くなってしまいます。

  • 以下のコードの1)と2)はrspecの実行プロセス内、3)は別サーバプロセスから実行される。

# 1)
let!(:user) { create(:user) }
before { user.posts << create(:post) }

# 2)
context 'use rack test' do
  # do something
end

# 3)
context 'use js driver', js: true do
  # do something
end

設定内容

rspecのcofigurationでbefore(:each)毎にDatabaseClearnerのstrategyを切り替えるようにすることで、jsdriverが必要なところだけtruncationでDBクリアされるようになります。


Capybara.javascript_driver = :poltergeist

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before :suite do
    DatabaseCleaner.strategy = :transaction
    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