こんにちは、とまだです。
テスト自動化あるある言いたい by T-DASH Advent Calendar 2024、8日目の記事をお届けします!
皆さん、テストは書いていますか?
最近、テストの自動化を進めていく中で、時間に関するテストで思わぬハマりポイントがあることに気づきました。
今回は、時間にまつわるテストで遭遇しやすい問題と、その対策をご紹介します!
1. 現在時刻を使ったテストがコケる
よくある問題
実行時の時刻に依存したテストは、以下のような問題を引き起こすことがあります。
- テストの実行タイミングでコケる
- タイムゾーンが違う環境でコケる
- たまに処理に時間がかかった時にコケる
対策方法
現在時刻を固定値に置き換えましょう。
明示的に時刻を指定することで、テストの安定性が向上します。
# 良い例
it "1日後の期限でタスクが作成されること" do
base_time = Time.new(2024, 1, 1, 12, 0, 0) # 2024/01/01 12:00:00
travel_to base_time do # 現在時刻を固定
task = create_tomorrow_task # 1日後のタスクを作成
expect(task.deadline).to eq(base_time + 1.day) # 期限が1日後であることを確認
end
end
2. 月末日のテストでハマる
よくある問題
月末日の処理を含むテストでは、以下のような問題が起きることがあります。
- 月によって日数が違う
- うるう年の判定
- 月をまたぐ計算が複雑
「年」を指定しているのであれば大体問題はないのですが、「月末」を使っている場合は要注意です。
対策方法
適当な日付でいいのであれば、中間日を使います。
# 良い例:15日を使用
let(:base_date) { Date.new(2024, 1, 15) }
# 悪い例:31日を使用
let(:base_date) { Date.new(2024, 1, 31) }
ただし、月末であることがロジックに絡むのであれば、境界値のテストは絶対に書くようにしましょう。
3. 時差が絡むテストで混乱する
よくある問題
国際的にサービスを提供する場合、以下のような問題が発生するかもしれません。
- サーバとクライアントのタイムゾーンが違う
- 日付変更線をまたぐ処理がある
- サマータイムの影響
対策方法
テスト内では UTC を使用し、必要に応じてタイムゾーンを明示的に指定します。
# 良い例
it "日本時間で正しく表示されること" do
time = Time.utc(2024, 1, 1, 12, 0, 0) # UTC で指定
expect(format_time(time, "Asia/Tokyo")).to eq "2024/01/01 21:00" # 日本時間で表示
end
もちろん、タイムゾーンによってロジックが変わる場合は、そのテストも書くようにしましょう。
4. 経過時間のテストが不安定になる
よくある問題
処理時間を含むテストでは、以下のような問題が発生します。
- 実行環境によって処理時間が変わる
- 負荷状況で結果が変わる
- 微妙な時間差で失敗する
「再実行したら通った」という経験がある方も多いのではないでしょうか。
その場合には、時間の比較を見直した方がいいかもしれません。
対策方法
具体的な時間ではなく、相対的な比較や範囲での判定を使います。
# 良い例
it "1分以内にジョブが完了すること" do
start_time = Time.now # 開始時刻を記録
perform_job # ジョブを実行
expect(Time.now - start_time).to be < 60 # 1分以内で完了することを確認
end
もちろん、タイムアウトなどが絡む場合には、そのテストも書くようにしましょう。
まとめ
時間を扱うテストで気をつけるべきポイントを見てきました。
- 現在時刻は固定値を使う
- 月末日は避けて中間日を使う
- タイムゾーンは明示的に指定する
- 経過時間は範囲で判定する
これらの点に気をつければ、より安定したテストが書けるはずです!
最後まで読んでいただき、ありがとうございました。
他にもアドベントカレンダー記事を書いています!
他にも、2024 年のアドベントカレンダーに参加しています。
以下の記事でまとめているので、よければ他の記事も読んでいただけると嬉しいです!