Ruby-on-rails 工厂女孩创建绕过我的模型验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9322353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Factory-girl create that bypasses my model validation
提问by Norto23
I am using Factory Girl to create two instances in my model/unit test for a Group. I am testing the model to check that a call to .current returns only the 'current' groups according to the expiry attribute as per below...
我正在使用 Factory Girl 在我的模型/单元测试中为一个组创建两个实例。我正在测试模型以检查对 .current 的调用是否仅根据到期属性返回“当前”组,如下所示...
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
My problem is that I've got validation in the model that checks a new group's expiry is after today's date. This raises the validation failure below.
我的问题是我在模型中得到了验证,该模型检查新组的到期时间是在今天的日期之后。这会引发下面的验证失败。
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
Is there a way to forcefully create the Group or get around the validation when creating using Factory Girl?
有没有办法在使用 Factory Girl 创建时强制创建组或绕过验证?
回答by Brandan
This isn't very specific to FactoryGirl, but you can always bypass validations when saving models via save(:validate => false):
这不是 FactoryGirl 特有的,但是在通过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
回答by Jason Denney
I prefer this solution from https://github.com/thoughtbot/factory_girl/issues/578.
我更喜欢https://github.com/thoughtbot/factory_girl/issues/578 中的这个解决方案。
Inside the factory:
工厂内部:
to_create {|instance| instance.save(validate: false) }
EDIT:
编辑:
As mentioned in the referenced thread, and by other's comments/solutions, you'll likely want to wrap this in a trait block to avoid confusion/issues elsewhere in your tests; for example, when you're testing your validations.
正如在引用的线程中以及其他人的评论/解决方案中所提到的,您可能希望将其包装在一个 trait 块中,以避免在您的测试中的其他地方出现混淆/问题;例如,当您测试验证时。
回答by Tim Scott
It's a bad idea to skip validations by default in factory. Some hair will be pulled out finding that.
默认情况下在工厂中跳过验证是一个坏主意。发现会拔掉一些头发。
The nicest way, I think:
最好的方法,我认为:
trait :skip_validate do
to_create {|instance| instance.save(validate: false)}
end
Then in your test:
然后在你的测试中:
create(:group, :skip_validate, expiry: Time.now + 1.week)
回答by Chris Habgood
foo = build(:foo).tap{ |u| u.save(validate: false) }
回答by Gabe Martin-Dempesy
回答by HAZI
It is not best to skip all validation of that model.
最好不要跳过对该模型的所有验证。
create spec/factories/traits.rbfile.
创建spec/factories/traits.rb文件。
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
回答by acamino
Your factories should create valid objects by default. I found that transient attributescan be used to add conditional logic like this:
默认情况下,您的工厂应该创建有效的对象。我发现瞬态属性可用于添加这样的条件逻辑:
transient do
skip_validations false
end
before :create do |instance, evaluator|
instance.save(validate: false) if evaluator.skip_validations
end
In your test:
在您的测试中:
create(:group, skip_validations: true)
回答by JoaoHornburg
Depending on your scenario you could change validation to happen only on update. Example: :validates :expire_date, :presence => true, :on => [:update ]
根据您的情况,您可以将验证更改为仅在更新时发生。例子::validates :expire_date, :presence => true, :on => [:update ]
回答by brcebn
Or you can use both FactoryBotand Timecopwith something like:
或者您可以同时使用FactoryBot和Timecop,例如:
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) }
Edit: Do not update this event after creation or validations will fail.
编辑:创建后不要更新此事件,否则验证将失败。

