Custom Validator
RailsにおけるCustom ValidatorについてはRuby on Rails Guidesや「てめえらのRailsはオブジェクト指向じゃねえ!まずはCallbackクラス、Validatorクラスを活用しろ!」などの記事に触れられているとおりである.
Modelはごちゃごちゃさせたくないし,Validatorとして切りだしちゃえば使い回しも効くよね!という話(ざっくり).
Validatorのテスト
Custom ValidatorのテストについてはRailsでCustom validatorをテストするにて言及されている.
特定のModelに依存したテストを書くのはおかしな話だからダミーのクラスを用意しよう!みたいな感じ.
let(:model_class) do Struct.new(:url) do include ActiveModel::Validations def self.name 'DummyModel' end validates :url, full_http_url: true end end
ただ,これを各Validator Spec毎に毎回書くのは面倒だなーと思う.サボりたい.
RSpec::ValidatorSpecHelper
ということで,Validatorのテストで手抜きするためのgemを作った(izumin5210/rspec-validator_spec_helper).
勝手にダミークラスを生成してvalidates
やvalidates_with
も設定してくれるというものになっている.
EachValidator
継承クラスの場合は1つのカラムにしか依存しないので,let
を利用してvalue
に値を突っ込むことでvalidateしてくれる.
あとはis_expected
やワンライナーshould
等でbe_valid
/be_invalid
を見てあげればよい(subject
にダミークラスをnewしたものが入ってる).
describe EmailValidator, type: :validator do
describe '#validate_each' do
context 'with invalid format address' do
let(:value) { 'kokoro.pyonpyon' }
it { is_expected.to_not be_valid }
end
context 'with valid foramt address' do
let(:value) { 'kokoro.pyonpyon@example.com' }
it { is_expected.to be_valid }
end
end
end
EachValidator
じゃない(Validator
を直接継承している)場合は,validationに関係するカラム名をattribute_names
として渡してあげる.
describe NotOverlappedValidator, type: :validator do
let(:attribute_names) { [:begin_at, :end_at] }
let(:begin_at) { Time.parse("2014-12-24T12:00:00+09:00") }
describe '#validate' do
context 'when end_at is overlapped' do
let(:end_at) { Time.parse("2014-12-24T09:00:00+09:00") }
it { is_expected.to_not be_valid }
end
context 'when end_at is not overlapped' do
let(:end_at) { Time.parse("2014-12-24T19:00:00+09:00") }
it { is_expected.to be_valid }
end
end
end
値を宣言するだけでValidationのテストができるので,とても楽になる.