Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

RSpec で安全に Timecop する

More than 1 year has passed since last update.

タイトルは釣りで、実はTimecopは不要という話をします。てへぺろ

Rails 4.1 以降、 ActiveSupport に travel/travel_to メソッドが実装されたのでこれを使おう。
https://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html
travel には相対時間(1日前、とか)、 travel_to には時刻(2000年1月1日とか) を指定して使う。
いずれも Timecop の freeze 相当で時間の流れは止まる。

使用するには include が必要。 rails_helper.rb に1行追加する

RSpec.configure do |config|
  #...
  config.include ActiveSupport::Testing::TimeHelpers
  #...
end

travel しておいて travel_back し忘れると他のテストに影響してしまうため、以下のように block 内で処理すると安全。

context "leap day" do
  around do |e|
    travel_to('2016-2-29 10:00'.to_time){ e.run }
  end
  it { is_expected.to be_success }
end

to_time は 自動的にやってくれるので、実は以下のようにも書ける。可読性アップ。

    travel_to('2016-2-29 10:00'){ e.run }

ところで、 Timecop だと可能な block のネストが travel/travel_to では出来ない
http://qiita.com/akicho8/items/4b2b12786a385ef94731
という指摘があり、これに対応する issue が出されたりもしたが、最終的に Rails コミュニティが出した結論は「ネストするな」ということで、5.1.0 以降はブロックのネストで例外が発生するようになった。
https://github.com/rails/rails/pull/24890
block の中で block 無しをコールするのは許されており、その場合効果は累積される。ブロックを抜けた段階で travel_back してフルリセットされる。ブロック内で travel_back を呼んでしまうとその行以降は普通の現在時刻に戻ってしまうので注意。

context "leap day" do
  around do |e|
    travel_to('2016-2-29 10:00'){ e.run }
  end
  it do
    travel -1.day
    expect(Date.current).to eq '2016-2-28'.to_date
    # もしここで travel_back すると
    # この行は2月29日ではない
  end
end

時間をずらしたうえで freeze はさせたくない場合や、時間の進み方を変えたい場合は Timecop を使おう。
滅多にないけど。

heartrails
ハートレイルズは、新規事業の立ち上げに伴うウェブサービス、スマホアプリの企画、開発、運用に特化した開発会社です。
http://www.heartrails.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away