【问题标题】:FactoryGirl define attribute by calling method on another factoryFactoryGirl 通过调用另一个工厂的方法来定义属性
【发布时间】:2013-04-14 13:35:31
【问题描述】:

这是来自 FactoryGirl documentation 的示例:

FactoryGirl.define do
  factory :post do
    name "Post name"
    user
  end
end

在此示例中,user 正在调用另一个工厂。我想做的是有效地调用user.id,但将其设置为属性的定义。这是一个精简的示例:

**models/job.rb**
  ...
  belongs_to :assignee, :class_name => "User"
  belongs_to :user
  ...
  attr_accessible :assignee_id, :user_id
  ...
end


**factories/jobs.rb**
FactoryGirl.define do
  factory :job do
    assignee_id user.id      #what I would like to do, but triggers "undefined method 'id'" error
    user_id user.id          #user_id is an attribute of the model and is the job assignor
 end

我已尝试合并文档中讨论别名的部分,但没有成功:

FactoryGirl.define do
  factory :user, :aliases => [:assignee] do
  ....

我觉得(希望?)我在这里很近,但任何见解都值得赞赏。谢谢。

编辑:这段代码让我的规范运行!

**factories/jobs.rb**

FactoryGirl.define do
  factory :job do
    before(:create) do |job|
      user = FactoryGirl.create(:user)
      job.assignee = user
      job.user  = user
    end

  association :assignee, factory: :user
  association :user, factory: :user
  sequence(:user_id) { |n| n }
  sequence(:assignee_id) { |n| n }
  ...
end

它通过了我的 it { should be_valid } 规范,所以看起来工厂很好,尽管我认为当我调用 FactoryGirl.create 时我对规范本身进行了一些重构。

上面的代码结合了 mguymon 的建议。谢谢!

最终更新

在回去重读Hartl's discussion on model associations之后,我才得以平息这件事。我上面的内容在技术上是有效的,但是当我在我的规范中构建或创建工作时,实际上并没有正确传递属性。这是我应该拥有的:

FactoryGirl.define do
  factory :job do
    association :assignee, factory: :user
    user
  end
end

我的问题还源于我是如何在规范中创建工厂的,所以我应该这样做(但不是...叹息):

    let(:user) { create(:user) }
    before { @job = create(:job, user: @user) }

我的工厂似乎不需要明确地有association :user,也不需要上面的before 块。

顺便说一句,我还了解到我可以通过在expect 语句中包含puts @job 进行调试,或者调用@job.assignee_id 以确保属性被正确加载。当运行该特定规范时,puts 语句将在规范中的 F. 旁边输出。

【问题讨论】:

  • 抱歉,您能显示异常堆栈跟踪吗?谢谢

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


【解决方案1】:

对于最新版本的 FactoryGirl,使用 association 映射到其他 ActiveRecord 模型:

factory :job do
  # ...
  association :assignee, factory: :user
end

这是直接来自the docs


根据您发布的错误,它表明您正在尝试获取 user.iduser 不是 ActiveRecord 实例,而是来自 FactoryGirl 的代理。如果您使用association 方法,则不会出现此错误。如果您需要直接访问模型,则必须先手动构建它。你可以通过在你的工厂中传递一个 block 来做到这一点:

factory :job do
    assignee_id { FactoryGirl.create(:user).id }
end

您似乎试图关联同一个模型两次,为此您可以使用before_create 回调创建一个用户模型并分配给userassignee

factory :job do

  before(:create) do |job|
      user = FactoryGirl.create(:user)
      job.assignee = user
      job.user = user
  end
end

【讨论】:

  • 感谢您的回答和链接。即使有关联(我确定需要),我仍然收到“未定义的方法 'id'”错误。
  • 您的编辑成功了。现在我的规范终于运行了,我需要通过并修复一些重复用户引起的麻烦故障......
  • 原来我不需要`before(:create),也不需要从工厂创建用户。尽管我的工厂测试为有效,但它没有正确地将属性加载到我在规范中创建或构建的作业中(我通过在规范中使用 puts @job 验证了这一点)。我已经在我的问题中添加了正确的代码(或者,至少是一个更好的版本......也许有一个“更正确”的版本),但我将你的答案作为检查答案,因为我明确需要关联受让人与用户,如果没有你的帮助就不会得到它。
猜你喜欢
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多