web-dev-qa-db-fra.com

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 les éléments suivants 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)

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

[~ # ~] modifier [~ # ~]

Après quelques recherches, je n'ai trouvé, c'est probablement une façon `` ok '' de tester cela, shoulda ne fournit rien pour cela et toute personne qui en a besoin peut écrire son propre matcher personnalisé (et probablement le contribuer de nouveau 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 les plages et non une liste de valeurs. La correspondance personnalisée peut être basée sur cela.

40
jake

Utilisez shoulda_matchers

Dans les versions récentes de shoulda-matchers (au moins à partir de la 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]) }
65
Nathan Long

Si vous avez plus d'éléments à tester qu'un booléen O/N, 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 la %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
25
nmott

J'ai trouvé un adaptateur de shoulda personnalisé (dans l'un des projets sur lesquels je travaillais) qui tente de s'approcher pour 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 de base de données qui explose quand il essaie de l'enregistrer. J'essaierai de donner l'essence de l'idée. Les matchs? la mise en œuvre 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 modifions légèrement ce qui précède pour dire @subject.save et laissez Rails explose, nous pouvons retourner false lorsque la chaîne d'exception contient quelque chose qui 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 ne serait pas une mauvaise idée d'ajouter à votre projet en tant que matcher personnalisé si vous voulez vraiment tester beaucoup de :inclusion validation.

1
jake