6

这个简单的例子使用 DataMapper 的before :save回调(又名钩子)来增加callback_count. callback_count 被初始化为 0 并且应该被回调设置为 1。

当通过以下方式创建 TestObject 时调用此回调:

TestObject.create()

但是当 FactoryGirl 通过以下方式创建回调时,会跳过回调:

FactoryGirl.create(:test_object)

知道为什么吗?[注意:我正在运行 ruby​​ 1.9.3、factory_girl 4.2.0、data_mapper 1.2.0]

详细信息如下...

数据映射器模型

# file: models/test_model.rb
class TestModel
  include DataMapper::Resource

  property :id, Serial
  property :callback_count, Integer, :default => 0

  before :save do
    self.callback_count += 1
  end
end

FactoryGirl 声明

# file: spec/factories.rb
FactoryGirl.define do
  factory :test_model do
  end
end

RSpec 测试

# file: spec/models/test_model_spec.rb
require 'spec_helper'

describe "TestModel Model" do
  it 'calls before :save using TestModel.create' do
    test_model = TestModel.create
    test_model.callback_count.should == 1
  end
  it 'fails to call before :save using FactoryGirl.create' do
    test_model = FactoryGirl.create(:test_model)
    test_model.callback_count.should == 1
  end
end

测试结果

Failures:

  1) TestModel Model fails to call before :save using FactoryGirl.create
     Failure/Error: test_model.callback_count.should == 1
       expected: 1
            got: 0 (using ==)
     # ./spec/models/test_model_spec.rb:10:in `block (2 levels) in <top (required)>'

Finished in 0.00534 seconds
2 examples, 1 failure
4

3 回答 3

3

至少对于factory_girl 4.2(不知道从哪个版本开始支持),通过使用自定义方法来持久化对象还有另一种解决方法。正如在 Github 中对有关它的问题的回应中所述,这只是调用save而不是save!.

FactoryGirl.define do
  to_create do |instance|
    if !instance.save
      raise "Save failed for #{instance.class}"
    end
  end
end

当然它并不理想,因为它应该在 FactoryGirl 核心中起作用,但我认为现在它是最好的解决方案,目前,我与其他测试没有冲突......

需要注意的是,您必须在每个工厂中定义它(但对我来说这不是不方便)

于 2013-06-14T09:42:07.053 回答
1

解决了。

@Jim Stewart 向我指出了这个 FactoryGirl 问题,它说“FactoryGirl 在 [它创建的] 实例上调用保存!”。在 DataMapper 的世界中,save!明确地不运行回调——这解释了我所看到的行为。(但它没有解释为什么它适用于@enthrops!)

同一个链接提供了一些专门针对 DataMapper 的解决方法,我可能会选择其中一个。不过,如果未修改的 FactoryGirl 与 DataMapper 配合得很好,那就太好了。

更新

这是thoughtbot 的 Joshua Clayton 建议的代码。我将它添加到我的spec/factories.rb文件中,test_model_spec.rb现在通过没有错误。凉豆。

# file: factories.rb
class CreateForDataMapper
  def initialize
    @default_strategy = FactoryGirl::Strategy::Create.new
  end

  delegate :association, to: :@default_strategy

  def result(evaluation)
    evaluation.singleton_class.send :define_method, :create do |instance|
      instance.save ||
        raise(instance.errors.send(:errors).map{|attr,errors| "- #{attr}: #{errors}"    }.join("\n"))
    end

    @default_strategy.result(evaluation)
  end
end

FactoryGirl.register_strategy(:create, CreateForDataMapper)

更新 2

出色地。也许我说得太早了。添加 CreateForDataMapper 修复了该特定测试,但似乎破坏了其他测试。所以我暂时不回答我的问题。其他人有好的解决方案吗?

于 2013-03-05T20:56:21.730 回答
1

使用 build 来构建您的对象,然后手动调用 save ...

t = build(:test_model)
t.save
于 2015-01-22T21:12:29.017 回答