RSpec / Rails / Ruby
この記事はRuby on Rails Advent Calendar 2015の3日目です。
DatabaseCleanerでテスト実行毎にデータを削除する
RSpecでテストをする際に、各テストケースの実行毎にデータベースの状態をクリアしてくれるdatabase_cleanerというgemがあります。
このgemはとても便利で、rails_helper.rb
に以下のような感じで設定しておくと他のテストの影響を受けずに各テストケースを実行できます。
DatabaseCleanerのAUTOCOMMIT問題
ただ、transaction strategyで実行している場合はDatabaseCleaner.clean
実行後もAUTOCOMMIT
されたデータが削除されません。
そのため「個別にテストを実行すると成功するのにrake spec
では失敗する」といったことが起きてしまう場合があります。
AUTOCOMMIT問題の対策
で、そのための対策なのですが、rails_helper.rb
に
を追加して、AUTOCOMMIT
が行われるテストケースに
とtruncation: true
を設定します。
こうするとこのテストケースはtruncation strategyで実行するのでAUTOCOMMITされたデータも削除してくれます。
AUTOCOMMITされるテストケースを見つける
ただ、どのテストケースでAUTOCOMMIT
が行われているのかをひとつひとつ確認するのは大変です。
なので、各テストケース終了後にデータが残っていないか確認するようにしておくと便利です。
例えば
のようにしておくと、各テストケースの実行後にデータが残っている場合にちゃんとテストを失敗させることができます。
ちなみにunscoped
はdefault_scope
の影響を除外するために追加しています。
問題のあるテストケースが見つかれば、あとはtruncation: true
を設定するだけです。
チェックするモデルの選び方
全てのモデルのチェックをテスト実行毎に行うとテスト実行時間が長くなってしまうので、必要なモデルだけチェックするようにしましょう。
例えばBlog::Site
がBlog::User
に依存している場合はBlog::Site
のチェックは不要です。
依存先がないモデルは全てチェックした方が良いのですが、全モデルのチェックは問題があった時に行うだけにして、毎回チェックするモデルは絞り込みましょう。
まとめ
テスト後にデータが残っているとAUTOCOMMIT
されたテストケースは成功するのに、その後で別のテストが失敗したりするので原因を探すのが結構大変です。
しかもテストの実行順によって時々失敗したり、失敗するテストケースも異なったりします。
この状態で放置しているとCIが機能しなくなってしまうので、AUTOCOMMIT
したデータはしっかり削除するようにしましょう。
最後に最終的なrails_helper.rb
の内容も載せておきます。