読者です 読者をやめる 読者になる 読者になる

database cleanerの設定について

rails

rspecのテスト実行時にDatabaseCleanerを使用しています。

データベースを毎回キレイな状態にしてくれるやつですね。

これの何がいいかというと、テストデータが固定化されるのと、増えないのでテストの実行が遅くならないということです。

ただし、設定によってテストが遅くなることもあります。

きちんとした設定をすることが高速化につながります。

そして、設定について、曖昧だったのでまとめておきます。

transactionとtruncationについて

trancationはDBを毎回削除しています。

truncate文ですね。

transactionはDBをrollbackしています。

手元で実行速度を確認したかったので、試してみました。

truncation

Finished in 11.22 seconds (files took 0.45743 seconds to load)
45 examples, 0 failures, 1 pending

transaction

Finished in 10.94 seconds (files took 0.45952 seconds to load)
45 examples, 0 failures, 1 pending

若干ながら、transactionの方が早いですね。

公式のドキュメントにも、transactionの方が早いって謳ってます。

For the SQL libraries the fastest option will be to use :transaction as transactions are simply rolled back. If you can use this strategy you should.

しかし、少しだけ問題があります。

However, if you wind up needing to use multiple database connections in your tests (i.e. your tests run in a different process than your application) then using this strategy becomes a bit more difficult. You can get around the problem a number of ways.

javascriptのテストを実行するときようなときは注意が必要です。

transactionの問題点

jsのテストを実行する場合は、ブラウザで動いているプロセスから、データベースの値が取得できなくてテストが落ちてしまいます。

transactionの場合は、transaction内でデータを生成しますが、別のスレッドからはデータを取得できないからです。

公式にも書いていますが、下記のようにfeatureテストのみtrancationを使用するようにします。

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so continue to use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      # Driver is probably for an external browser with an app
      # under test that does *not* share a database connection with the
      # specs, so use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

また、下記の部分もfalseに変更します。

  config.use_transactional_fixtures = false

挿入するデータをtransactionするのではなく、truncationするようになります。

ここの常にtruncationする必要はないため、特定の時だけfalseにする設定ができれば、処理が早くなりそうな気がします。

まとめ

DB 別のスレッドからデータ参照
truncation truncate(削除)
transaction rollback ×

適当に設定していたけど、意外に奥が深くて面白いですね。