Comment tester quelle validation a échoué dans ActiveRecord?

J'ai un modèle comme ceci:

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

Je veux tester cette validation:

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

Mais alors il ne teste pas quel type d'erreur a été défini sur name. Je veux savoir si c'était le cas too_short, too_long, ou peut-être qu'une autre validation a échoué.

Je peux rechercher le texte du message dans le tableau errors, comme ceci:

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

Mais cela échouera lorsque je définirai activerecord.errors.messages.too_short dans un fichier de paramètres régionaux au lieu d'un message spécifique au modèle.

Alors, est-il possible de vérifier quel type d'erreur s'est produite?

25
demandé sur Jan Dudek 2010-11-07 22:49:17

4 réponses

Rails a ajouté une méthode pour rechercher des erreurs dans ActiveModel à la fin de 2011 et Rails v3. 2. Il suffit de vérifier pour voir si l'erreur a été #added?:

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

# An error added after validation
record.email = 'taken@email.com'
record.valid? # => false
record.errors.added? :email, :taken # => true

Notez que pour les validations paramétrées (par exemple :greater_than_or_equal_to), vous devrez également passer la valeur du paramètre.

record.errors.add(:age, :greater_than_or_equal_to, count: 1)
record.errors.added?(:age, :greater_than_or_equal_to, count: 1)
Les erreurs

Sont identifiées par leur clé i18n. Vous pouvez trouver les clés appropriées pour vérifier dans le fichier Rails i18n approprié pour n'importe quelle langue sous l'erreur section .

Certains autres astucieux questions que vous pouvez poser ActiveModel#Error sont #empty? et #include?(attr), ainsi que tout ce que vous pouvez demander à un Enumerable.

39
répondu fny 2016-03-18 15:45:22

Je n'aime vraiment pas l'idée de chercher des messages d'erreur traduits dans le hachage des erreurs. Après une conversation avec un autre Rubyists, j'ai terminé le hachage des erreurs de correction de singe, de sorte qu'il enregistre le message non traduit en premier.

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

Ensuite, vous pouvez tester comme ceci:

u = User.new(:name => "a")
u.valid?
u.errors.error_names[:name].should include(:too_short)
12
répondu Jan Dudek 2010-11-24 22:01:06

Je recommande de vérifier la gem shoulda pour gérer ces types de tests de validation répétitifs. Il complète RSpec ou Test:: Unit afin que vous puissiez écrire des spécifications concises telles que:

describe User do
  it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) }
end
5
répondu Peter Brown 2010-11-07 20:15:59

L'approche que j'utilise:

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

J'utilise une expression rationnelle pour correspondre au message d'exception car il peut y avoir beaucoup de messages de validation dans le message d'exception, mais nous voulons nous assurer qu'il contient un extrait spécifique relatif au nom étant trop court.

Cette approche couple vos assertions à vos messages de validation, donc si vous modifiez chaque message de validation, vous devrez probablement modifier vos spécifications. Dans l'ensemble cependant, c'est un moyen simple d'affirmer des validations font leur travail.

4
répondu Ben5e 2012-10-15 18:28:27