Usine fille créer qui court-circuite ma validation de modèle
-
27-10-2019 - |
Question
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 au retour .Current seuls les groupes « courants » selon l'attribut d'expiration comme 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 j'ai validation dans le modèle qui vérifie l'expiration d'un nouveau groupe est postérieure à la date d'aujourd'hui. 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
Est-il possible de créer avec force le groupe ou contourner la validation lors de la création en utilisant Factory Girl?
La solution
Ce n'est pas très spécifique à factorygirl, mais vous pouvez toujours contourner lors de l'enregistrement des modèles de validation 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
Autres conseils
Je préfère cette solution de https://github.com/thoughtbot/factory_girl/issues/578 .
A l'intérieur de l'usine:
to_create {|instance| instance.save(validate: false) }
EDIT:
Comme mentionné dans le fil référencé, et par d'autres solutions de commentaires /, vous voudrez sans doute envelopper ce dans un bloc de trait pour éviter toute confusion / problèmes ailleurs dans vos tests; par exemple, lorsque vous testez validateurs.
Il est une mauvaise idée de sauter par défaut dans la validation usine. Certains cheveux seront tiré constater que.
La plus belle façon, je pense:
trait :skip_validate do
to_create {|instance| instance.save(validate: false)}
end
Ensuite, dans votre test:
create(:group, :skip_validate, expiry: Time.now + 1.week)
Pour cette date-baesd cas de validation spécifique, vous pouvez également utiliser la pierre précieuse Timecop pour modifier temporairement le temps pour simuler l'ancien record en cours de création dans le passé.
foo = build(:foo).tap{ |u| u.save(validate: false) }
Vos usines devraient créer des objets valides par défaut. J'ai trouvé que transitoire attributs peut être utilisé pour ajouter la 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)
Il est préférable de ne pas sauter toutes la validation de ce modèle.
créer un fichier spec/factories/traits.rb
.
FactoryBot.define do
trait :skip_validate do
to_create { |instance| instance.save(validate: false) }
end
end
spec fix
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
En fonction de votre scénario vous pouvez changer la validation de se produire uniquement sur la mise à jour. Exemple: :validates :expire_date, :presence => true, :on => [:update ]