web-dev-qa-db-ja.com

Railsでの包含検証をRSpecを使用してテストするにはどうすればよいですか?

ActiveRecordに次の検証があります。

validates :active, :inclusion => {:in => ['Y', 'N']}

モデル検証をテストするために以下を使用しています。

should_not allow_value('A').for(:active)
should allow_value('Y').for(:active)
should allow_value('N').for(:active)

これをテストする方法により、よりクリーンでもっとありますか?私は現在RSpec2とshouldaマッチャーを使用しています。

[〜#〜]編集[〜#〜]

周りを見回した後、私はただこれをテストするのにおそらく「OK」な方法であることがわかりました.shouldaはこれに対して何も提供せず、それを必要とする誰もがそれのために独自のカスタムマッチャーを書くことができます(そしておそらくプロジェクトにそれを貢献します) 。興味をそそられるかもしれない議論へのいくつかのリンク:

  • 上記へのリンク。 リンク1リンク2

  • should_ensure_value_in_rangeこれは使用できるものに近づきますが、値のリストではなく範囲のみを受け入れます。カスタムマッチャーはこれに基づくことができます。

40
jake

Shoulda_matchersを使用する

shoulda-matchersの最近のバージョン(少なくともv2.7.0以降)では、次のことができます。

expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N])

これは、検証で受け入れ可能な値の配列がこの仕様に正確に一致することをテストします。

以前のバージョンの> = v1.4では、shoulda_matchersは次の構文をサポートしています。

it {should ensure_inclusion_of(:active).in_array(%w[Y N]) }
65
Nathan Long

ブールY/Nよりもテストする要素が多い場合は、試すこともできます。

_it "should allow valid values" do
  %w(item1 item2 item3 item4).each do |v|
    should allow_value(v).for(:field)
  end
end
it { should_not allow_value("other").for(:role) }
_

また、%w()をモデルで定義した定数に置き換えることで、定数値のみが許可されていることをテストできます。

_CONSTANT = %w[item1 item2 item3 item4]
validates :field, :inclusion => CONSTANT
_

次に、テスト:

_it "should allow valid values" do
  Model::CONSTANT.each do |v|
    should allow_value(v).for(:field)
  end
end
_
25
nmott

私は次のようなものをテストするために近づこうとしている(私が取り組んでいたプロジェクトの1つで)1つのカスタムshould matcherを見つけました:

例:

it { should validate_inclusion_check_constraint_on :status, :allowed_values => %w(Open Resolved Closed) }
it { should validate_inclusion_check_constraint_on :age, :allowed_values => 0..100 }

マッチャーは、それを保存しようとすると失敗するDB制約があることを確認しようとします。アイデアの本質を説明しようとします。試合?実装は次のようになります。

  begin
    @allowed_values.each do |value|
      @subject.send("#{@attribute}=", value)
      @subject.save(:validate => false)
    end
  rescue ::ActiveRecord::StatementInvalid => e
    # Returns false if the exception message contains a string matching the error throw by SQL db
  end

上記を少し変更して@subject.saveとRails検証を爆発させます。例外文字列に実際の例外エラーメッセージとほぼ一致するものが含まれている場合、falseを返すことができます。

これがプロジェクトに貢献するのに完璧とは程遠いことは知っていますが、本当にたくさんの:inclusion検証。

1
jake