はじめに
あるユーザーのログイン履歴一覧を取得するAPIを作成した際のテストにて、時刻の扱い方で躓いたため整理しておきます。
前提
ユーザー(accounts)テーブルと、そのログイン履歴(logins)テーブルがある時。
やりたいこと
以下のようなデータを作成。
let(:login1_created_at) { 4.day.ago }
let!(:login1) { create(:login, account: account, created_at: login1_created_at) }
この状態でsubject
を走らせ、created_at
の値が一致することをテストしたい。
困ったこと
response
で返ってきたaccountのcreated_at
と、let!
で作成したaccountのcreated_at
が一致しない。
原因
これはRubyのTimeオブジェクトの仕様でcreated_at
にて作成したデータはミリ秒まで含んでしまうためです。
ちなみに以下のコードで検証すると、それぞれ以下のような値が返ってきます。
subject
res = JSON.parse(response.body)
expect(Time.zone.parse(res["data"].to_s)).to eq login1.created_at.to_time
-
response
Sun, 01 Aug 2021 14:58:19.000000000 JST +09:00
-
let1!
2021-07-30 14:58:19.384332 +0900
let1!で作成したデータはミリ秒以下の細かい数字が出てしまい一致しませんでした。
解決
結論、ミリ秒以下の正確な値の検証は必要ないため、以下のようにto_s
としてミリ秒以下を切り捨てることで解決しました!
let!(:login1) { create(:login, account: account, created_at: login1_created_at.to_s) }
# 結果
2021-07-30 14:58 +0900
まとめ
時刻に関するテストでは正確に一致するのを確認するのは難しいため、以下のようなメソッドを使う方法も検討すると良いかもしれません。
-
be_within
- 指定した秒数は切り捨てられる
-
travel_to
- it の下に定義することで任意の時間を指定して、テストを走らせることができる。