ECサイトの開発では、「購入時刻の処理が正しく動いているか?」をテストする場面が多くあります。
たとえば、以下のようなケースです。
- 予約販売の商品が、指定の時間より前に購入できてしまわないか?
- タイムセールの終了時刻を過ぎても割引が適用されていないか?
- 一定期間内の購入回数をカウントするロジックが正しく機能しているか?
こうしたテストを行う際、いちいちシステム時刻を変更するのは現実的ではありません。
そこで便利なのが Timecop というgemです。
Timecopの導入方法
まず、Gemfile
に以下を追加し、bundle install
を実行します。
group :test do
gem 'timecop'
end
Timecopの基本的な使い方
時刻を固定する (Timecop.freeze
)
require 'timecop'
Timecop.freeze(Time.local(2025, 1, 1, 12, 0, 0)) do
puts Time.now # => 2025-01-01 12:00:00
end
puts Time.now # 実際の現在時刻が表示される
過去や未来にジャンプする (Timecop.travel
)
Timecop.travel(Time.local(2025, 12, 31)) do
puts Time.now # => 2025-12-31 00:00:00
end
時の流れを遅くする (Timecop.scale
)
Timecop.scale(3600) # 1秒が1時間に相当するスピードで時間が進む
ECの購入時刻のテストにTimecopを活用する
例えば、「午前10時~11時限定のタイムセール」 のロジックが正しく動作するかテストしたい場合、以下のように実装できます。
describe 'タイムセールの価格適用' do
it '10:00〜10:59の間は割引価格になる' do
Timecop.freeze(Time.local(2025, 1, 1, 10, 30)) do
product = Product.find(1)
expect(product.discounted_price).to eq(500) # 割引価格
end
end
it '11:00以降は通常価格に戻る' do
Timecop.freeze(Time.local(2025, 1, 1, 11, 0)) do
product = Product.find(1)
expect(product.discounted_price).to eq(1000) # 通常価格
end
end
end
Timecopを使う際の注意点
-
Timecop.freeze
を使ったら、ensure
ブロックでTimecop.return
を呼ぶか、ブロック内で使う -
Time.now
を直接参照するコードでのみ有効(外部APIのタイムスタンプには影響なし)
まとめ
EC開発では、購入時刻に関するテストが重要になります。
Timecopを使えば、自由に時間を操りながら簡単にテストを実装できる ので、ぜひ活用してみてください!