見出し画像

【開発ブログ】RSpecで時間を操作してテストする

こんにちは。24年度新卒の ryoaio です。

私の所属するチームは2024年7月に立ち上がり、この半年で体制やメンバーを変えつつ、経験を積みながら形成してきました。

半年はあっという間ですね...! 今年も多くのことを経験し、個人としてもチームとしても強くなっていきます💪

さて、本日は、最近触ったRSpecの時間の操作に関してまとめたいと思います。


RSpecで時間操作をすることになったきっかけ

「start_time ~ end_timeまでの期間を指定して情報を取得するようなGETメソッドにて、end_timeが現在時間よりも未来を指していた場合、未来のデータが仮にあったとしても、現在時間までのデータを返すようにする」 という実装を行いました。

この際、RSpec上正しく返されているかを確認するために、時間の操作が必要でした。

RSpecで時間を止める方法は複数ある

Timecopを使う

github.com

  • Railsのgem

    • Time, Date, DateTimeオブジェクトのオーバーライドによる実装

  • .freezeで現在時間を完全に停止

  • .travelで指定した時間に固定したり、指定した時間からの経過を測れるようにする

TimeHelpersを使う

api.rubyonrails.org

  • Railsの組み込み

    • 4.1以降が対応

  • fleeze_timeで現在時間を完全に停止

  • travelや travel_to で指定時間に固定

  • travel_backで現在時刻に戻す

    • 5.2以前ではtravel_backをするまでテスト中時間が止まり続ける

    • 5.2以降ではテスト終了時に自動的に元に戻る

今回の課題の解決

以下理由でTimeHelpersを使いました。

  • どちらの方法でもできることに大きな違いがないため

  • 今回やりたいことは日時の固定のみとシンプルで、gemを導入せずとも問題なくテストができそうだったため

時間操作時の注意点

ミリ秒の誤差が生じてテストが落ちることがある

TimeHelpersのドキュメントに次のような記載があります。

Note that the usec for the time passed will be set to 0 to prevent rounding errors with external services, like MySQL (which will round instead of floor, leading to off-by-one-second errors).

実際、時間を指定して固定するだけでは、テストが落ちてしまうことがありました。

# 時間を固定し、operate時に time:にcurrent_timeが入ること
         current_time = Time.zone.now
         travel_to current_time

         target.operate

         expect(Target.find(target.id)).to have_attributes(
            time: current_time,
         )

一見問題なさそうに見えますが、以下のように期待していた値から差ができ、テスト失敗となってしまいます。

   (expedcted)    -:time => 2025-02-05 07:59:11.384651543 +0000,
   (got)          +:time => 2025-02-05 07:59:11.000000000 +0000,

Timeクラスで使えるusecの指定によって、期待値を調整しておきましょう。

# 時間を固定し、operate時に time:にcurrent_timeが入ること
         current_time = Time.zone.now.change(usec: 0)
         travel_to current_time

         target.operate

         expect(Target.find(target.id)).to have_attributes(
            time: current_time,
         )

これでOKです!

実際、上記例のようにtravel_toで現在時間を固定した上で、固定した日時より未来の日時でリクエストを送り、固定した日時までのデータが返されていることを確認できました!

最後に

ご覧いただきありがとうございました。

私のチームは、伸び代の宝庫です。まだまだスクラムが不安定であったりと、試行錯誤する毎日。 そういった学びの共有はまた、チームの成長を実感し、言語化できるようになった時にしたいと思います。


いいなと思ったら応援しよう!

株式会社インゲージ|お問い合わせ管理ツール「Re:lation」#SaaS
記事を読んでいただいてありがとうございます。これからも情報発信を続けていきます。