カレーの恩返し

おいしいのでオススメ。

DB共有しているRailsアプリケーションのテストを書くときに気をつけること

これで2時間くらい潰れたので供養のために書いておく。

TL;DR

DatabaseCleanerのstrategyがtransactionになってると、もう一方のRailsアプリケーションに反映されないから気をつけよう

遭遇したこと

2つのRailsアプリケーションで1つのDBを共有しているサービスで以下のようなテストを書いていた。

  1. Rails 2 がレコードを作成する
  2. Rails 2 がRails1に対して作成したレコードのidを渡しAPI callをする
  3. Rails 1 が受け取ったidのレコードを取得し、中身を書き換える
  4. Rails 2 で中身が書き換わったことを確かめる
# めちゃくちゃ雑な図解

             Rails 1                Rails 2
                |                     |
                |                 a = A.create!
                |                     |
          A.find(a.id)                |
      a.update!(foo: "bar")           |
                |                     |
                |          expect(a.foo).to eq "bar"
                |                     |

実行すると、A.find(a.id)がResourceNotFoundを返してテストが落ちていた。
テストコードを何回見直してもおかしい箇所は見当たらず、悲しい気持ちになっていたら database_cleanerが悪いことをしている気がしたので確認してみると、

RSpec.configure do |config|
  ...
  condig.before do |_|
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.start
  end
  ...
end

database_cleanerのstrategyがtransactionに設定されていた。
なので変更してもDB自体にはcommitされていなかったためにRails 1から作成したレコードは見えていなかった。

よく考えると当たり前なんだけど、問題に直面するとなかなか気づかなかったりするのでメモメモ。