Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
88
Help us understand the problem. What is going on with this article?
@izumin5210

【Rails】まだValidatorのテストで消耗してるの?

More than 5 years have passed since last update.

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

- RailsでCustom validatorをテストする - Qiita

ただ,これを各Validator Spec毎に毎回書くのは面倒だなーと思う.サボりたい.

RSpec::ValidatorSpecHelper

ということで,Validatorのテストで手抜きするためのgemを作った(izumin5210/rspec-validator_spec_helper).
勝手にダミークラスを生成してvalidatesvalidates_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のテストができるので,とても楽になる.

References

88
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
izumin5210
ʕ ◔ϖ◔ʔ < I'm a Rubyist.
wantedly
「シゴトでココロオドル」ためのビジネスSNS「Wantedly」の開発・運営をしています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
88
Help us understand the problem. What is going on with this article?