課題
当日の日付との比較を行う処理を validates_timeliness
の on_or_before
を使って記述しているが、RSpecにテストを記述する際に日付の固定がうまくできず( Timecop
も travel_to
もNG )、現在日時との比較になってしまう。
# 未来日の入力はエラーとする validates_date :date, on_or_before: Time.zone.now.to_date
原因
日付固定の外で対象のクラスが読み込まれてしまっている。
RSpec.describe Hoge, type: :model do before(:each) do # Timecop.freeze(Time.zone.local(2019, 10, 10)) travel_to Time.zone.local(2019, 10, 10) end
ファイルの前後に日付をセットしていたので内部で実行されるクラスには固定した日時が採用されるかと思っていたが、RSpec.describe Hoge
の行が評価される時点で Hogeの読み込みが行われ、validatesに定義している処理は時間を固定する前の値で評価されてしまっていたようだ。
対応(旧)
クラスを引数にするから評価されてしまうからそれを回避しよう、ということで文字列にしてみた。
RSpec.describe 'Hoge', type: :model do
この書き方だと何か別な問題があるのかもしれないがテストは通るようになった。
対応(新)
validates
のところで直接時刻評価を記述しているから評価されてしまうので、メソッドに退避してみたら上手くいった。
RSpec.describe Hoge, type: :model do validate :day_after_tomorrow private def day_after_tomorrow unless errors.include? :date validates_date :date, on_or_before: Time.zone.now.to_date, allow_blank: true end end
ちなみにメソッド名と中身は一致してない。