今回はRSpecで現在日時(Time.currentやTime.zone.now)をテストする3つの方法についてまとめてみました。コード内で現在日時を使用した場合、そのテストコードでは現在日時部分が固定されていないため少し工夫する必要があります。今回はその解決方法を3つ紹介したいと思います。この記事の内容RSpecでは正確な日時は特定できない現在時刻をテストする3つの方法テスト実行前の現在日時と評価時の現在時刻を用いるtravel_toを用いて現在日時を固定するTimecopを用いて現在日時を固定するまとめ参考RSpecでは正確な日時は特定できない以下のようにコード内で現在日時を使用している場合、RSpecではTime.currentで日時を設定するタイミングが異なるため正確な日時を特定することはできません。+0900現在時刻をテストする3つの方法テスト実行前の現在日時と評価時の現在時刻を用いる1つ目の方法はテスト実行前に現在日時を保存し、その日時が評価時の現在時刻との間にあるかをチェックするようにします。今回はテスト実行前の現在日時をstart_timeとして保存しています。endendインスタンスの値を更新するためreloadが必要です。expect(post.reload.posted_at)travel_toを用いて現在日時を固定するRails4.1以降、ActiveSupportにtravel_toメソッドが実装され、それを用いることで現在日時を固定しテストすることができます。test.Time.now、Date.today、およびDateTime.nowをスタブして、このメソッドに渡された時刻または日付を返すことにより、現在の時刻を指定された時刻に変更します。スタブは、テストの終了時に自動的に削除されます。ActiveSupport::Testing::TimeHelperstravel_toメソッドを使用するにはrails_helper.rbにincludeする必要があるため、まずは以下の記述を忘れずに追記しましょう。省略endtravel_toメソッドを用いて投稿日時が更新されるテストは、以下のように記述することができます。aroundでtravel_toを囲んでおくことで、他のitでも現在日時が固定されるので便利です。endend以下のようにbeforeブロックで囲んで使用することもできます。endendRails5.2系以前はtravel_toで日時を固定した場合、以下のように必ずtravel_backで時間を戻しておく必要がありました。endendしかし5.2系にてこれを修正するPRが出されマージされているため、travel_backは不要になりました。activesupport/lib/active_support/testing/time_helpers.rbの修正です。moduleでafter_teardownメソッドを定義し、テスト終了時に自動でtravel_backを呼び出すよう修正しています。これにより、block無しのtravelやtravel_toを使用した場合に、明示的にtravel_backを呼ぶ必要は無くなります。caseで一度同様の対応が削除された事があったのですが、自動でtravel_backした方が便利だろう、という事で再度入ったようです。log流し読み(2017/07/24)Timecopを用いて現在日時を固定するtravel_toではなく、Timecopというgemを用いることでも現在日時を固定することが可能です。以下の手順でrspec-timecopを導入しましょう。installこれでTimecop.freezeで日時を固定することができるようになりました。endendtravel_toの場合と同じように、beforeブロックで囲んで使用することもできます。endendTimecopで時間を固定した際は、Timecop.returnで時間を戻しておく必要があります。上記コードではafterブロックで使用していますが、以下のようにspec_helper.rbに設定を追記しておいても良いかもしれません。log流し読み(2017/07/24)今回はRSpecで現在日時をテストする3つの方法について紹介しました。個人的にはtravel_toを用いて現在日時をテストする方が最もシンプルで正確なのかなと思います。-fではなく--force-with...Railsエンジニアちばよしはる銀座にあるヘルステック企業のRailsエンジニア。初心者から中級者向けに記事を更新しています。お酒とカレーと競馬が好き。TechTechMedia。