首页 > 解决方案 > 如何在 Rails 5.2 上测试与 FactoryBot 的多态关联?

问题描述

我编写基本测试来指定在模型级别进行的验证。我使用 Rspec 和 FactoryBot。BusinessObject 模型可以有 2 个父模型:BusinessArea 或 BusinessProcess。

BusinessObject 模型的提取:

# == Schema Information
#
# Table name: business_objects
#
#  id                 :integer          not null, primary key
#  playground_id      :integer          not null
#  main_scope_id      :integer
#  code               :string(30)       not null
#  name               :string(200)      not null
#  description        :text
#  area_process_type  :string
#  area_process_id    :integer

class BusinessObject < ActiveRecord::Base
  belongs_to :area_process, polymorphic: true
  validates :area_process, presence: true
...
end

BusinessArea 模型的摘录:

class BusinessArea < ActiveRecord::Base
  has_many :business_objects, as: :area_process
...
end

BusinessProcess 模型的摘录:

class BusinessProcess < ActiveRecord::Base
  has_many :business_objects, as: :area_process
...
end

工厂:

FactoryBot.define do
  factory :business_object do
    association :area_process,  factory: :business_area
    name                {"Test Business Object"}
    code                {"TEST_BO"}
    description         {"This is a test Business object used for unit testing"}
    created_by          {"Fred"}
    updated_by          {"Fred"}
    owner_id            {1}
    status_id           {0}
    end

end

运行测试时,Factory 失败并显示以下消息:

7) BusinessObject 有一个有效的工厂失败/错误:expect(build(:business_object)).to be_valid

 ActiveRecord::StatementInvalid:
   PG::UndefinedColumn: ERROR:  Column business_objects.business_area_id does not exist.

如何向工厂指定要在关联中使用的父级?

非常感谢!

标签: ruby-on-railsfactory-bot

解决方案


我在这里找到了解决方案,https://github.com/thoughtbot/factory_bot/issues/1226

为 business_area 和 business_process 定义工厂。在 business_object 工厂中写这样的东西

factory :business_object do
  #define attributes
  transient do
    area_process { nil }
  end

  area_process_id { area_process.id }
  area_process_type { area_process.class.name }
end

并且在规范中

let(:business_area) { create(:business_area) }
let(:business_object) { create(:business_object, area_process: business_area) }

推荐阅读