Comment puis-je tester: validation d'inclusion dans Rails en utilisant RSpec

J'ai la validation suivante dans mon ActiveRecord.

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

J'utilise ce qui suit pour tester mes validations de modèle.

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

Y a-t-il un moyen plus propre et plus efficace de tester cela? J'utilise actuellement RSpec2 et shoulda matchers.

Modifier

Après avoir regardé autour de moi, j'ai seulement trouvé, c'est probablement une façon " ok " de tester cela, shoulda ne fournit rien pour cela et quiconque en a besoin peut écrire son propre matcher personnalisé pour cela.(Et sans doute y contribuer en retour au projet). Quelques liens vers des discussions qui pourraient être intéressantes:

  • Liens qui indiquent à ce qui précède . Lien 1 , Lien 2

  • should_ensure_value_in_range celui-ci se rapproche de ce qui peut être utilisé, mais n'accepte que des plages et non une liste de valeurs. Matcher personnalisé peut être basé sur cela.

33
demandé sur jake 2011-09-14 15:34:27

3 réponses

Utiliser shoulda_matchers

Dans les versions récentes de shoulda-matchers (au moins à partir de v2. 7. 0), Vous pouvez faire:

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

Cela teste que le tableau de valeurs acceptables dans la validation correspond exactement à cette spécification.

Dans les versions antérieures, > = v1. 4, shoulda_matchers prend en charge cette syntaxe:

it {should ensure_inclusion_of(:active).in_array(%w[Y N]) }
57
répondu Nathan Long 2014-11-25 19:46:14

Si vous avez plus d'éléments à tester qu'un y/n booléen, vous pouvez également essayer.

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) }

Vous pouvez également remplacer le %w() par une constante que vous avez définie dans votre modèle afin qu'il teste que seules les valeurs constantes sont autorisées.

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

Puis le test:

it "should allow valid values" do
  Model::CONSTANT.each do |v|
    should allow_value(v).for(:field)
  end
end
23
répondu nmott 2011-10-18 03:59:49

J'ai trouvé un shoulda matcher personnalisé (dans l'un des projets sur lesquels je travaillais) qui tente de se rapprocher de tester quelque chose comme ceci:

Exemples:

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 }

Le matcher essaie de s'assurer qu'il y a une contrainte DB qui explose quand il essaie de l'enregistrer.Je vais tenter de donner l'essence de l'idée. Les matchs? l'implémentation fait quelque chose comme:

  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

Je suppose que si nous changeons légèrement ce qui précède pour dire @subject.save et que la validation des Rails explose, nous pouvons revenir false lorsque la chaîne d'exception contient quelque chose qui se ferme correspond au message d'erreur d'exception réel.

Je sais que c'est loin d'être parfait pour contribuer au projet, mais je suppose que ce n'est pas une mauvaise idée à ajouter dans votre projet en tant que matcher personnalisé si vous voulez vraiment tester beaucoup de la validation :inclusion.

1
répondu jake 2011-09-22 03:04:37