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
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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クリアされるようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
comments powered by Disqus