Factory-girl创建绕过我的模型验证

时间:2012-02-17 03:10:28

标签: ruby-on-rails ruby-on-rails-3 rspec factory-bot rspec-rails

我正在使用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

我的问题是我在模型中进行了验证,检查新组的到期时间是在今天的日期之后。这会在下面引发验证失败。

  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

在使用Factory Girl创建时,有没有办法强制创建组或绕过验证?

9 个答案:

答案 0 :(得分:76)

这不是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

答案 1 :(得分:49)

我更喜欢https://github.com/thoughtbot/factory_girl/issues/578的解决方案。

工厂内部:

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

修改

正如引用的帖子和其他人的评论/解决方案中所提到的,您可能希望将其包装在特征块中,以避免在测试中的其他地方出现混淆/问题;例如,当您测试验证时。

答案 2 :(得分:22)

默认情况下,在工厂中跳过验证是一个坏主意。发现一些头发会被拉出来。

最好的方式,我想:

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

然后在你的测试中:

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

答案 3 :(得分:7)

对于此特定的基于日期的验证案例,您还可以使用timecop gem暂时更改时间以模拟过去创建的旧记录。

答案 4 :(得分:4)

foo = build(:foo).tap{ |u| u.save(validate: false) }

答案 5 :(得分:1)

根据您的方案,您可以将验证更改为仅在更新时发生。示例::validates :expire_date, :presence => true, :on => [:update ]

答案 6 :(得分:1)

您的工厂应默认创建有效对象。我发现transient attributes可以用来添加这样的条件逻辑:

transient do
  skip_validations false
end

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

在你的测试中:

create(:group, skip_validations: true)

答案 7 :(得分:1)

最好不要跳过对该模型的所有验证。

创建spec/factories/traits.rb文件。

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

修复规范

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

答案 8 :(得分:0)

或者您可以将FactoryBotTimecop都使用类似以下内容:

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) }

编辑:创建后请勿更新此事件,否则验证将失败。