テストでタイムゾーンを考慮した
テストのプラクティスにて
Date型への変換メソッドのテストを行いました。
テストの観点
対象のメソッドは下記です。
app/models/report.rb
class Report < ApplicationRecord belongs_to :user has_many :comments, as: :commentable, dependent: :destroy validates :title, presence: true validates :content, presence: true def created_on created_at.to_date end
Reportモデルのメソッドで、型変換を行っています。
irb(main):014:0> Report.columns_hash['created_at'].type => :datetime # これがclass Date に変換されていたらOK
注意点!
まず自分は型チェックのみの実装を行いました。
#型チェック assert_not_equal Date, report.created_at.class assert_equal Date, report.created_on.class
テストの方針にもよるでしょうが、
reportの期待値が一致するか?
つまり、インスタンス生成時のcreated_atもチェックしてみるべきなのです。
そして初期の実装がこちら。
test '#created_on' do me = User.create(email: 'me@example.com', password: 'password') report = Report.create(user_id: me.id, title: 'タイトル', content: '内容') #型チェック assert_not_equal Date, report.created_at.class assert_equal Date, report.created_on.class #期待値のチェック assert_not_equal Date.today, report.created_at assert_equal Date.today, report.created_on
実はこちらバグになりうる問題点があります。
何か分かりますか?
Date.todayしたときの注意点
Date.todayを行うと普通に今日が取得できると思いますよね?
でもこれってどこを参照してどうやってできるのか?まったく把握していませんでした。
指摘をもらったのがこのタイムゾーンについてです。
フィヨルドでも大変お世話になっている、伊藤さんのめちゃくちゃ分かりやすい記事↓
抜粋:
# todayは環境変数のタイムゾーンを使う。(ただし、タイムゾーン情報は保持されない) l Date.today => 2015/01/01, Date # currentはapplication.rbのタイムゾーンを使う。 l Date.current => 2014/12/31, Date # Time.zone.todayはDate.current と同じ l Time.zone.today => 2014/12/31, Date
環境変数のタイムゾーンを使うか、またはapplication.rbのタイムゾーンを使うのか。
ここを知っておかなければ、テストは通ったのに本番環境でバグが起こるなんてことも??
まとめ
特に理由がなければ Time(RailsならTimeWithZone)を使う < 完全な受け売り
ただ今回のテスト対象のメソッドって、Dateに型変換するメソッドなので、私は分かりやすい様に、
Date.currentにて実装しました。
★Date.todayは使わない!
以上です。