LoginSignup
5
5

More than 5 years have passed since last update.

Factory Girl の sequence でハマった

Posted at

Railsプロジェクトで、RSpec+Factory Girlを使ってテストを書いていて、
ローカルでテストを走らせると問題なく通るのだけど、Travis CI上ではFが出るという不思議な現象が起きて、解決するまでに少し時間がかかったので、メモを残しておく。

例えばUserとHistoryというモデルがあって、1対Nで対応している。
テストの中でUser.joins(:histories)のようにINNER JOINしたものを使う必要があったので、Factory Girlで以下のように書いた。

factory :user, class: User do
    sequence(:id) { |n| n+1000 }
    …
end

factory :history, class: History do
    sequence(:id) { |n| n }
    sequence(:user_id) { |n| n+1000 } #ここをuserのidと揃える
    …
end

RSpecにはこう書く。以下、Aの場所と呼ぶ。

before(:each) do
    100.times { create(:user) }
    100.times { create(:history) }
end

(今回は1対N (N>1)の状態でテストする必要はなくて、1対1でも良かったのでこういう書き方をしている。)

このAのあとでUser.joins(:histories)をすればUser.joins(:histories).sizeは100になるはずなんだけど、0になってしまう問題が起きてFが出ていた。

原因は別の場所(以下、Bの場所と呼ぶ) で
1000.times { create(:history) }
をしていて、historyのuser_idがuser.idよりも1000進んでいて、INNER JOINの時に一致したidがなかったということ。

spec_helper.rbconfig.order = "random"にして、順番がランダムに行われるようにしているのだけど、ローカルでrspecを走らせた時には、BよりもAの方が先に実行されたため、historyのuser_idとuser.idが一致していて、JOINが問題なくできたためテストをパスできたのだけど、
Travis CIでテストを走らせた時には(7回中7回とも)、AよりもBの方が先に実行されたため、JOINが上手くできなくてFが出ていた。

ハマった理由は3つで、

  • before(:each) を使えば毎回テストの前に状態がリセットされて、今回であれば毎回idが1001から作られると思っていた。
  • Rails 4.1.5から4.1.7にあげた途端に7回連続でFailしたため、(ありえない気がするけど)Railsのアップデートと何か関係があるのかと思って、そっちの方向でしばらく考えてしまった。
  • 4.1.5ではTravisで成功(2回試行)、4.1.7ではローカルではテストが成功する(3回試行)のに、Travisのみで失敗する(7回試行)という脅威の運の悪さ(1/(2**12) = 0.024%)によって、Travisの環境になにか問題があるのかと考えていた。

ということで、解決方法としては

factory :user4join, class: User do
    sequence(:id) { |n| n+1000 }
    …
end

factory :history4join, class: History do
    sequence(:id) { |n| n }
    sequence(:user_id) { |n| n+1000 } #ここをuserのidと揃える
    …
end

みたいにJOINする専用のデータを作って、単にcreate(:hitstoy)するのとは分けておくのがいいんですかね。
この辺、常識なのかもしれないですけど、ハマったのでメモしておきました。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5