【问题标题】:Factory-girl create that bypasses my model validation绕过我的模型验证的工厂女孩​​创建
【发布时间】:2012-03-08 12:06:48
【问题描述】:

我正在使用 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 创建时,有没有办法强制创建组或绕过验证?

【问题讨论】:

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


    【解决方案1】:

    这并不是 FactoryGirl 特有的,但您在通过 save(validate: false) 保存模型时始终可以绕过验证:

    describe ".current" do
      let!(:current_group) { FactoryGirl.create(:group) }
    
      let!(:old_group) do
        g = FactoryGirl.build(:group, expiry: Time.now - 3.days)
        g.save(validate: false)
        g
     end
          
     specify { Group.current.should == [current_group] }
    end
    

    【讨论】:

    • 查看下面 Jason Denney 的回答以获得更好的解决方案。
    • 从 1.9.1 开始你可以做g.tap { |g| g.save(validate: false) }
    【解决方案2】:

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

    工厂内部:

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

    【讨论】:

    • 这是一个比公认的更优雅的解决方案。
    • 请记住,如果您为通用工厂执行此操作,那么您每次在该工厂创建时都会跳过验证。最好只在子工厂(或特征)上使用这种技术。
    • 你几乎肯定会想把它放在一个特征中。请参阅下面 Tim Scott 的答案。
    【解决方案3】:

    在工厂默认跳过验证是个坏主意。发现这一点会拔掉一些头发。

    我认为最好的方法:

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

    然后在你的测试中:

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

    【讨论】:

    • 有没有办法将此应用于所有工厂?
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:
      foo = build(:foo).tap { |u| u.save(validate: false) }
      

      【讨论】:

        【解决方案6】:

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

        创建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
        

        【讨论】:

          【解决方案7】:

          默认情况下,您的工厂应该创建有效的对象。我发现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)
          

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              或者您可以同时使用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) }
              

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

              【讨论】:

                猜你喜欢
                • 2013-04-22
                • 1970-01-01
                • 2012-01-03
                • 1970-01-01
                • 2013-05-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多