web-dev-qa-db-fra.com

Factory-girl crée qui contourne la validation de mon modèle

J'utilise Factory Girl pour créer deux instances dans mon modèle/test unitaire pour un groupe. Je teste le modèle pour vérifier qu'un appel à .current ne renvoie que les groupes "actuels" en fonction de l'attribut d'expiration décrit ci-dessous ...

  describe ".current" do
    let!(:current_group) { FactoryGirl.create(:group, :expiry => Time.now + 1.week) }
    let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }

    specify { Group.current.should == [current_group] }
  end

Mon problème est que le modèle vérifie que l'expiration d'un nouveau groupe est postérieure à la date du jour. Cela soulève l'échec de validation ci-dessous.

  1) Group.current 
     Failure/Error: let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }
     ActiveRecord::RecordInvalid:
       Validation failed: Expiry is before todays date

Existe-t-il un moyen de forcer la création du groupe ou de contourner la validation lors de la création à l'aide de Factory Girl?

59
Norto23

Ce n'est pas très spécifique à FactoryGirl, mais vous pouvez toujours contourner les validations lors de l'enregistrement de modèles via save(:validate => false):

describe ".current" do
  let!(:current_group) { FactoryGirl.create(:group) }
  let!(:old_group) {
    g = FactoryGirl.build(:group, :expiry => Time.now - 3.days)
    g.save(:validate => false)
    g
  }

  specify { Group.current.should == [current_group] }
end
72
Brandan

Je préfère cette solution de https://github.com/thoughtbot/factory_girl/issues/578 .

À l'intérieur de l'usine:

to_create {|instance| instance.save(validate: false) }

MODIFIER:

Comme mentionné dans le fil de discussion, et dans les commentaires/solutions d'autres personnes, vous voudrez probablement envelopper ceci dans un bloc de traits pour éviter toute confusion/problème ailleurs dans vos tests; par exemple, lorsque vous testez vos validations.

49
Jason Denney

Ignorer les validations en usine est une mauvaise idée. Certains cheveux seront arrachés pour le trouver.

Le meilleur moyen, je pense:

trait :skip_validate do
  to_create {|instance| instance.save(validate: false)}
end

Puis dans votre test:

create(:group, :skip_validate, expiry: Time.now + 1.week)
21
Tim Scott

Pour ce cas de validation spécifique basé sur la date, vous pouvez également utiliser la gemme timecop pour modifier temporairement le temps afin de simuler l'ancien enregistrement créé précédemment.

7
Gabe Martin-Dempesy
foo = build(:foo).tap{ |u| u.save(validate: false) }
4
Chris Habgood

En fonction de votre scénario, vous pouvez modifier la validation afin qu'elle ne se produise que lors de la mise à jour. Exemple: :validates :expire_date, :presence => true, :on => [:update ]

1
JoaoHornburg

Vos usines devraient créer des objets valides par défaut. J'ai trouvé que les attributs transitoires peuvent être utilisés pour ajouter une logique conditionnelle comme ceci:

transient do
  skip_validations false
end

before :create do |instance, evaluator|
  instance.save(validate: false) if evaluator.skip_validations
end

Dans votre test:

create(:group, skip_validations: true)
1
acamino

Il est préférable de ne pas passer toute la validation de ce modèle.

créer le fichier spec/factories/traits.rb.

FactoryBot.define do
  trait :skip_validate do
    to_create { |instance| instance.save(validate: false) }
  end
end

fixer la spécification

describe ".current" do
  let!(:current_group) { FactoryGirl.create(:group, :skip_validate, :expiry => Time.now + 1.week) }
  let!(:expired_group) { FactoryGirl.create(:group, :skip_validate, :expiry => Time.now - 3.days) }

  specify { Group.current.should == [current_group] }
end
0
HAZI