web-dev-qa-db-ja.com

ActiveRecordで失敗した検証をテストする方法は?

私はこのようなモデルを持っています:

class User < ActiveRecord::Base
  validates_length_of :name, :in => (2..5)
end

この検証をテストしたい:

it "should not allow too short name" do
  u = User.new(:name => "a")
  u.valid?
  u.should have(1).error_on(:name)
end

ただし、nameに設定されたエラーの種類はテストされません。 too_shorttoo_long、または他の検証が失敗したかどうかを知りたいです。

次のように、エラー配列でメッセージテキストを検索できます。

u.errors[:name].should include(I18n.t("activerecord.errors.models.user.attributes.name.too_short"))

しかし、モデル固有のメッセージの代わりにロケールファイルにactiverecord.errors.messages.too_shortを設定すると、これは失敗します。

では、どのようなエラーが発生したかを確認することはできますか?

27
Jan Dudek

Rails 2011年後半にActiveModelにエラーをクエリするメソッドを追加しました。Rails v3.2 。適切なエラーがあったかどうかを確認してください _#added?_

_# An error added manually
record.errors.add :name, :blank
record.errors.added? :name, :blank # => true

# An error added after validation
record.email = '[email protected]'
record.valid? # => false
record.errors.added? :email, :taken # => true
_

パラメータ化された検証(例:_:greater_than_or_equal_to_)の場合、パラメータの値も渡す必要があることに注意してください。

_record.errors.add(:age, :greater_than_or_equal_to, count: 1)
record.errors.added?(:age, :greater_than_or_equal_to, count: 1)
_

エラーは、i18nキーによって識別されます。 エラーセクション の下にある任意の言語の適切な Rails i18n ファイルをチェックインするための適切なキーを見つけることができます。

_ActiveModel#Error_に尋ねることができる他の気の利いた質問には、 _#empty?_#include?(attr) 、および- Enumerable

39
fny

エラーハッシュで翻訳されたエラーメッセージを探すというアイデアは本当に好きではありません。仲間のRubyistsと会話した後、モンキーパッチのエラーハッシュを終了したので、翻訳されていないメッセージが最初に保存されます。

module ActiveModel
  class Errors
    def error_names
      @_error_names ||= { }
    end

    def add_with_save_names(attribute, message = nil, options = {})
      message ||= :invalid
      if message.is_a?(Proc)
        message = message.call
      end
      error_names[attribute] ||= []
      error_names[attribute] << message
      add_without_save_names(attribute, message, options)
    end

    alias_method_chain :add, :save_names
  end
end

次に、次のようにテストできます。

u = User.new(:name => "a")
u.valid?
u.errors.error_names[:name].should include(:too_short)
12
Jan Dudek

私が使用するアプローチ:

it "should not allow too short name" do
  u = User.new(:name => "a")
  expect{u.save!}.to raise_exception(/Name is too short/)
end

例外メッセージには多くの検証メッセージが含まれている可能性があるため、正規表現を使用して例外メッセージを照合しますが、名前が短すぎることに関連する特定のスニペットが含まれていることを確認したいと思います。

このアプローチでは、アサーションを検証メッセージに結合するため、検証メッセージを変更するたびに、仕様も変更する必要があります。ただし、全体として、これは検証が機能していることを表明する簡単な方法です。

5
Ben5e

これらのタイプの反復検証テストを処理するには、gem shoulda をチェックすることをお勧めします。 RSpecまたはTest :: Unitを補完するため、次のような簡潔な仕様を記述できます。

describe User do
  it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) }
end
5
Peter Brown