DRY FactoryGirl创建/构建钩子之后的处理

7
我希望能够简化工厂中创建/构建后的钩子函数,使其更符合DRY原则:

我想在我的工厂中DRY up创建/构建后的钩子:

FactoryGirl.define do

  factory :poll do

    sequence :title do |n|
      "MyPollTitle#{n}"
    end
    sequence :description do |n|
      "MyPollDescription#{n}"
    end
    user

    factory :poll_with_answers do

      ignore do
        answers_count 2
      end

      after(:build) do |poll, evaluator|
        evaluator.answers_count.times do
          poll.answers << build(:answer, poll: poll)
        end
      end

      after(:create) do |poll, evaluator|
        evaluator.answers_count.times do
          poll.answers << create(:answer, poll: poll)
        end
      end
    end
  end
end

我面临的问题是,似乎我无法在FG中定义方法?有没有什么方法可以使它更加DRY(Don't Repeat Yourself)?

2个回答

7
首先,在最近版本的FactoryGirl中,after(:create)会隐式地调用after(:build)

after(:build) - 在工厂被构建后调用(通过FactoryGirl.build、FactoryGirl.create)

https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#callbacks 所以在你的情况下,以下代码应该就足够了:
after(:build) do |poll, evaluator|
  evaluator.answers_count.times do
    poll.answers << build(:answer, poll: poll)
  end
end

然而,当你使用build_stubbed()代替build()时,after(:build)不会被触发,我在遇到这个问题时正试图做的就是这个。为了简化代码,事实证明你可以使用callback()方法来调用相同的块以供多个方法使用:

factory :user do
  callback(:after_build, :after_stub) do |user|
    do_something_with(user)
  end
end

1

这可能是一个便宜的技巧,但您可以在第二个工厂中创建一个lambda:

factory :poll_with_answers do
  ignore do
    answers_count 2
  end

  make_answers = lambda do |poll, evaluator, method|
    evaluator.answers_count.times do
      poll.answers << send(method, :answer, poll: poll)
    end
  end

  after(:build) do |poll, evaluator|
    make_answers.call poll, evaluator, :build
  end

  after(:create) do |poll, evaluator|
    make_answers.call poll, evaluator, :create
  end
end

我对这个模式一点也不满意,但至少它可以使代码更加DRY。


它应该可以解决问题。它与你的代码几乎等价,所以如果在lambda版本中评估器为nil,则在你的版本中也应该为nil。你能否给我两个版本的原始工作代码和得到nil值的代码(还有堆栈跟踪)。我目前没有足够的信息来进行调试。 - Stefan Kanev
你不需要再投入更多的工作,这并不太重要,我基本上只是想检查是否有快捷方式。无论如何,我在https://gist.github.com/3140033上创建了一个要点,您可以在那里查看模型,其余部分是1:1。 - wintersolutions
没关系,但是在查看代码后,我不知道evaluator是什么 :) - Stefan Kanev
它说它是一个类lol,但实际上它是一个持有对ignore属性(answers_count)的引用的FactoryGirl实例。如果我运行我的代码,我可以看到评估器不是nil,如果我运行你的代码,评估器是nil。我猜这是一些FactoryGirl异常导致的,这个库有点糟糕。 - wintersolutions
就我所知,我通过将lambda移动到工厂定义之外使类似的代码工作正常(当它在内部时,它会被method_missing捕获)。 - Shevaun
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接