追記:2019.09.23
こちらの記事で記載があるようにRails 5.2系からtravel_backを明示的に書かなくてもよくなった模様... shinkufencer.hateblo.jp
経緯:自分が出したプルリクだけ関係ないRSpecで落ちる
ここ数日、自分が修正したプルリクでだけ修正範囲と違うところでCIが落ちまくっていた...
なぜだろう?わからん...
時刻関係?でも... travel_to
使って書いて時間ちゃんと止めてるしなあ...
テストが落ちてた原因
Railsのテストヘルパー travel_to
メソッドを beforeブロックで使用した後、afterブロックで travel_back
を実行してなかった...
時刻を戻さないと(travel_backしないと)何が起こる?
一つのテストで停止した時刻が他のテスト実行時に戻されず、その他の時刻テストが落ちまくる...
なお、一見すると関係ないところで落ちているように見えるので、ランダムに落ちるテストかな?と錯覚してしまい問題に気付くのが難しい事態に...
悪い例(今回やってしまった実装)
before do travel_to(Time.current) end # ここの下にafterブロックを書いてtravel_backする必要がある
良い例
before do travel_to(Time.current) end after do travel_back end
travel_toの実装を確認してみる
rails/activesupport/lib/active_support/testing/time_helpers.rb
if block_given?
の分岐に入れば必ず travel_back
が実行されるが、ブロックを引数に渡されないと実行されないことがここで分かります!
def travel_to(date_or_time) <中略> if block_given? begin yield ensure travel_back end end end
自分の誤解
travel_to
したらテストごとに時間が勝手にロールバックされるもんだと思ってました...
ちなみに gem 'timecop'
を使った場合も時間固定した後で、afterブロックで return
しないと今回の件と同じことが起こるので注意!
補足:gem 'timecop'
の場合
before do Timecop.freeze(Time.zone.parse('2019-03-04 00:00:00')) end after { Timecop.return }
注意点
時刻判定テストの際は beforeブロックのtravel_to
はちゃんとafterブロックで travel_back
をしないとダメ!
なお、 travel_to
の引数にブロックを渡した場合は、 travel_to
だけで自動で travel_back
が処理の最後でコールされることを忘れずに!