前人未踏の領域へ WEB・インフラ・プログラミング全般編

フロントエンド、バックエンド、インフラ、言語など、アプリ開発、IOT以外の記録

RSpecでvalidates_dateの日付テストがうまくいかない

課題

当日の日付との比較を行う処理を validates_timelinesson_or_before を使って記述しているが、RSpecにテストを記述する際に日付の固定がうまくできず( Timecoptravel_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

ちなみにメソッド名と中身は一致してない。

/* Responsive: yes */