Ich verwende Factory Girl, um zwei Instanzen in meinem Modell- / Komponententest für eine Gruppe zu erstellen. Ich teste das Modell, um zu überprüfen, ob ein Aufruf von .current nur die 'aktuellen' Gruppen gemäß dem unten angegebenen Ablaufattribut zurückgibt ...
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
Mein Problem ist, dass ich eine Validierung im Modell habe, die überprüft, ob der Ablauf einer neuen Gruppe nach dem heutigen Datum liegt. Dies löst den folgenden Validierungsfehler aus.
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
Gibt es eine Möglichkeit, die Gruppe zwangsweise zu erstellen oder die Validierung zu umgehen, wenn Sie mit Factory Girl erstellen?
g.tap { |g| g.save(validate: false) }
Ich bevorzuge diese Lösung von https://github.com/thoughtbot/factory_girl/issues/578 .
In der Fabrik:
to_create {|instance| instance.save(validate: false) }
BEARBEITEN:
Wie im Thread, auf den verwiesen wird, und in den Kommentaren / Lösungen anderer erwähnt, möchten Sie dies wahrscheinlich in einen Merkmalsblock einschließen, um Verwirrung / Probleme an anderer Stelle in Ihren Tests zu vermeiden. Zum Beispiel, wenn Sie Ihre Validierungen testen.
quelle
Es ist eine schlechte Idee, Validierungen standardmäßig im Werk zu überspringen. Einige Haare werden herausgezogen, um das zu finden.
Der schönste Weg, denke ich:
trait :skip_validate do to_create {|instance| instance.save(validate: false)} end
Dann in Ihrem Test:
create(:group, :skip_validate, expiry: Time.now + 1.week)
quelle
Für diesen speziellen Fall der Datumsüberprüfung können Sie auch das Timecop- Juwel verwenden, um die Zeit vorübergehend zu ändern und den alten Datensatz zu simulieren, der in der Vergangenheit erstellt wurde.
quelle
foo = build(:foo).tap{ |u| u.save(validate: false) }
quelle
Es ist nicht am besten, die gesamte Validierung dieses Modells zu überspringen.
spec/factories/traits.rb
Datei erstellen .FactoryBot.define do trait :skip_validate do to_create { |instance| instance.save(validate: false) } end end
fix spec
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
quelle
Abhängig von Ihrem Szenario können Sie die Validierung so ändern, dass sie nur beim Update erfolgt. Beispiel:
:validates :expire_date, :presence => true, :on => [:update ]
quelle
Ihre Fabriken sollten standardmäßig gültige Objekte erstellen. Ich fand heraus, dass transiente Attribute verwendet werden können, um bedingte Logik wie folgt hinzuzufügen:
transient do skip_validations false end before :create do |instance, evaluator| instance.save(validate: false) if evaluator.skip_validations end
In Ihrem Test:
create(:group, skip_validations: true)
quelle
Oder Sie können beide
FactoryBot
undTimecop
mit so etwas wie:trait :expired do transient do travel_backward_to { 2.days.ago } end before(:create) do |_instance, evaluator| Timecop.travel(evaluator.travel_backward_to) end after(:create) do Timecop.return end end let!(:expired_group) { FactoryGirl.create(:group, :expired, travel_backward_to: 5.days.ago, expiry: Time.now - 3.days) }
Bearbeiten : Aktualisieren Sie dieses Ereignis nicht, nachdem die Erstellung oder Validierung fehlgeschlagen ist.
quelle