はじめに
Rails Tips の 11 回目です。連日の model のテストを簡単に書くための shared_example の紹介の続きです。しばらくは私の Shared example の雛形 (lib/templates/rspec/model/model_spec.rb
)を一つずつ解説していく形です。
# describe "<%= class_name %> クラスについて" do # context "order_sort_order" do # subject { described_class.order_sort_order } # it_behaves_like "昇順確認", 0, ->(o) { o.sort_order } # end # context "order_bar_desc" do # subject { described_class.order_bar_desc } # it_behaves_like "降順確認", 99999, ->(o) { o.bar } # end # # context "Class methods" do # subject { described_class } # # it_behaves_like "単一メソッド呼び出し" do # let(:test_set) do # { # foo: [nil, [true, false, true]], # } # end # end # end # describe "get_or_create method" do # subject { -> { described_class.get_or_create(*params) }} # context '既存のものを取得' do # let(:params) { [object.xxx, object.yyy] } # it_behaves_like "オブジェクト数が変化しない?", <%= class_name %> # end # # context '新規作成' do # let(:params) { [object.xxx, other.yyy] } # it_behaves_like "オブジェクトが1増えるか?", <%= class_name %> # end # end # end
降順確認
今日は「降順確認」になります。昨日に引き続きデータの並び替えに関するテストになります。年度 (year) は最近の年度が一番利用されることが多いので、降順で並び替えることのほうが多いです。昨日の昇順確認とは逆でどの値よりも大きい値を初期値に設定します。
context "order_year_desc" do subject { described_class.order_year_desc } it_behaves_like "降順確認", 2100, ->(y) { y.year } end
また、行事を示す event モデルも逆順に並べることが多いです。fixtures のテストデータは基本的に過去のものを用意しているので、今日を初期値に設定しています。
context "order_event_date_desc" do subject { described_class.order_event_date_desc } it_behaves_like "降順確認", Date.today, ->(o) { o.event_date } end
この shared_example は以下のようになります。昨日のものの不等号が反対になっているだけです。取得した Array に対して、Proc を呼び出し start で指定されたものと比較します。比較結果が start よりも小さければテストが通過します。評価が終わると現在の値を start に置き換えるので、すべての要素に対して常に前の値より小さい単調減少の関係にあることがテストできることになります。
shared_examples_for "降順確認" do |start, block| it "降順に並んでいること" do subject.each do |object| value = block.call(object) expect(value <=> start).to be <= 0 start = value end end end
正しく動作させるための実装
昨日と同様に、このテストが正しく通過するためには、モデルに対して scope を設定すればよいことになります。year
モデルにおける order_year_desc
は以下のようになります。逆順なので arel_table に desc を追加しています。
scope :order_year_desc, -> { order arel_table[:year].desc }
event
モデルにおける order_event_date_desc
も同様です。
scope :order_event_date_desc, -> { order arel_table[:event_date].desc }
おわりに
今日のネタは昨日とほとんど変わらない手抜きなものになりました。逆順なので考えられる最大値を設定する必要があるので、注意が必要ですね。