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

Nor*_*o23 68 rspec ruby-on-rails rspec-rails ruby-on-rails-3 factory-bot

我正在使用Factory Girl在我的模型/单元测试中为一个组创建两个实例.我正在测试模型以检查对.current的调用是否仅根据expiry属性返回'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
Run Code Online (Sandbox Code Playgroud)

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

  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
Run Code Online (Sandbox Code Playgroud)

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

Bra*_*dan 84

这不是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
Run Code Online (Sandbox Code Playgroud)

  • 从 1.9.1 开始你可以执行 `g.tap { |g| g.save(验证: false) }` (2认同)

Jas*_*ney 50

我更喜欢这个解决方案来自https://github.com/thoughtbot/factory_girl/issues/578.

工厂内部:

to_create {|instance| instance.save(validate: false) }
Run Code Online (Sandbox Code Playgroud)

编辑:

正如引用的线程和其他的注释/解决方案中所提到的,您可能希望将其包装在特征块中以避免测试中其他地方的混淆/问题; 例如,当您测试验证时.

  • 这是一个比公认的解决方案更优雅的解决方案. (5认同)
  • 请记住,如果您为通用工厂执行此操作,则每次在该工厂创建时都会跳过验证.最好只在子工厂(或特征)上使用这种技术. (5认同)

Tim*_*ott 27

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

最好的方式,我想:

trait :skip_validate do
  to_create {|instance| instance.save(validate: false)}
end
Run Code Online (Sandbox Code Playgroud)

然后在你的测试中:

create(:group, :skip_validate, expiry: Time.now + 1.week)
Run Code Online (Sandbox Code Playgroud)


Gab*_*esy 7

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


HAZ*_*AZI 7

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

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

FactoryBot.define do
  trait :skip_validate do
    to_create { |instance| instance.save(validate: false) }
  end
end
Run Code Online (Sandbox Code Playgroud)

修正规格

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
Run Code Online (Sandbox Code Playgroud)


Chr*_*ood 5

foo = build(:foo).tap{ |u| u.save(validate: false) }
Run Code Online (Sandbox Code Playgroud)