FactoryGirl to_create返回值

时间:2013-09-01 02:38:25

标签: factory-bot

根据我的理解,工厂''to_create'方法的返回值将被忽略。这意味着从工厂的'build'或'initialize_with'部分返回的对象是在测试中调用'create'时最终返回的对象。

就我而言,我使用的是存储库模式的变体。我正在覆盖工厂的'to_create'部分,以包含对存储库'save'方法的调用。此方法不会修改给定对象,但会返回表示原始持久形式的对象。

但是,从'build'块返回的实例是从工厂返回的,而不是在'to_create'块中创建的实例。在我的代码中,这意味着返回对象的“未加载”形式,而不是保存操作中具有更新属性(例如“id”)的对象。

有没有办法强制'create'的返回值是'to_create'块的结果还是在该块中生成的某个值?

class Foo
  attr_accessor :id, :name
  ...
end

class FooRepository
  def self.create(name)
    Foo.new(name) # this object is not yet persisted and has no .id
  end

  def self.save(foo)
    # this method must not guarantee that the original Foo instance
    # will always be returned
    ...
    updated_foo # this is a duplicate of the original object
  end

  ...
end

FactoryGirl.define do
  factory :foo, class: FooRepository do
    # create an example Foo
    initialize_with { FooRepository.create(name: "Example") }
    # save the Foo to the datastore, returning what may be a duplicate
    to_create {|instance| FooRepository.save(instance)}
  end
end

describe FooRepository do
  it "saves the given Foo to the datastore" do
    foo = create(:foo)
    foo.id #=> nil
    ...
  end
end

1 个答案:

答案 0 :(得分:4)

除了“raise an issue”之外,我没有给你答案,对不起。

默认的to_create回调如下所示:

$ grep to_create lib/factory_girl/configuration.rb
to_create {|instance| instance.save! }

主要问题是当您在其上调用save!时,ActiveRecord会自行修改。 FactoryGirl将忽略从to_create返回的所有新对象。

如果要覆盖默认创建策略,请快速入侵:

module FactoryGirl
  module Strategy
    class Create
      def association(runner)
        runner.run
      end

      def result(evaluation)
        evaluation.object.tap do |instance|
          evaluation.notify(:after_build, instance)
          evaluation.notify(:before_create, instance)
          instance = evaluation.create(instance) # <-- HACK
          evaluation.notify(:after_create, instance)
        end
      end
    end
  end
end

...或者对你的to_create钩子进行模仿Rails的就地修改:

to_create do |record|
  new_record = YourRepositoryHere.new.create(record)
  record.attributes = new_record.attributes # For example
  new_record # Return the record just in case the bug is fixed
end
祝你好运。 :(