例えば EC サイトを Rails でつくっていて、RSpec + database_cleaner でテストを行っているとして。商品カテゴリーデータ等の永続的なマスターデータを扱いたいときどうするかって話です。
最近 paperboy&co. に入社された @udzura さん(『パーフェクト Ruby』の共著者!)がヘルプしてくれたのですが、お役立ち情報なので共有しておきます。
なお、使用しているバージョンは下記のとおりです。
設定例
先に設定例を示して、その後に解説をします。
RSpec.configure do |config| #... config.use_transactional_fixtures = true config.before(:suite) do load Rails.root.join('db', 'seeds.rb') DatabaseCleaner.clean_with :truncation, { except: %w(categories brands) } end end
解説
(1) database_cleaner の clean する対象から除外
まず下記のように except
オプションを使えば、database_cleaner が clean する対象から除外するテーブルを指定することができます。
DatabaseCleaner.clean_with :truncation, { except: %w(categories brands) }
が、しかし、これだけでは、うまくいかなかったので、以下、解説を続けます。
(2) rspec spec だとうまくいくのに、rake spec だとこけていた
当初 db:seed
したうえで bundle exec rspec spec
だとテストがすべて通るのに、bundle exec rake spec
だとこけるテストがありました(マスターデータを取得するテスト)
で、bundle exec rake spec --trace
してみたら、db:test:purge
で DB が空っぽになっていたことが原因でした。
(3) テストを開始する直前に db:seed を実行する
なので、テストを開始する直前に db:seed を行うことにしました。それが下記の箇所です。
load Rails.root.join('db', 'seeds.rb')
各テストで、利用するマスターデータを都度作成する方法もあると思うのですが、毎回データをつくっては消すというのはコストが高いので、最初に一度だけ読み込むのが良いと思います。
(4) クリーンアップ機能の競合
次に直面したのが、
config.use_transactional_fixtures = true
と、database_cleaner の公式ドキュメントにも書いている下記の設定が競合するという問題。
config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end
結局 config.use_transactional_fixtures = true
の方を残しました(逆を残すとうまくいかなかった)
その他
database_clenaer の設定の詳細については、公式ドキュメントを参照してください。
truncation と transaction の違いに言及した日本語情報もあったので、貼っておきます。
あと、Ruby 2.0 以上しかサポートしていないけど、database_rewinder というものもあるようです。
というわけで @udzura さん、ありがとうございました。あと『パーフェクト Ruby』すごく役に立っています!

- 作者: Rubyサポーターズ,すがわらまさのり,寺田玄太郎,三村益隆,近藤宇智朗,橋立友宏,関口亮一
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/10
- メディア: 大型本
- この商品を含むブログ (22件) を見る