Rails Rspec before(:all) の誤解

before(:all) は一度だけ実行されるとのことなので、特定のレコードに対しての it をやりたくて、とある describe のくくりの中だけで使う一件レコードを生成すれば十分だと思ったので、以下みたいな感じで書いていた。

describe "another test..." do
  # do something
end

describe ".a_method" do
  before(:all) do
    FactoryGirl.create(:user) # FactoryGirl 使ってたので
  end 

  context "given 100" do
    # it { ... } なんかのテスト
  end
  
  context "given 200" do
    # it { ... } なんかのテスト
  end
end

で、実行してみたら、Rspec 終了後にデータが残された状態になってしまって、二度目のテストや、ほかのテストでデータの重複が起きて通らなくなってしまった。

モデルは FactoryGirl によって、メールアドレスがシーケンスで生成されるよくある感じの user モデルです。

describe “.a_method” の中だけで有効なレコードを作って、それが 100 をもらったときと、200 をもらったときのモデルメソッドのテストのつもりだった。

そもそも

そのレコードの属性をいじるテスト(it)が(このときはなかったけど)あったら、変更されたレコードに対して別の it が走ることになるので、よほど意図してない限りは良くないテストだ。

デフォルトの before(:each) なら、it ごとに before が走り、都度新しいレコードを生成するので、シーケンス番号はズレていくがテストは常に変更されてないレコードで行われる。

そのほうがいいに決まってんじゃん…。

データが消えない

:all でテストが走った後はデータベースがクリアされない。

:each は it ごとに before を繰り返すから、トランザクションでうまいことやってくれているのだろう。

:all で作っちゃったら、自前で削除しなきゃいけないっぽい。

it ごとに新規レコードでテストすべきなので、:each (before do でも同じ) で before を使った方がいい。

よっぽど理由があるテストやマスターデータ(?)とかには :all を使いそう。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする