我如何在FactoryGirl中为循环关联创建工厂?

时间:2012-09-07 15:20:28

标签: ruby-on-rails ruby unit-testing associations factory-bot

我一直在努力为我在项目中定义的某些对象和关联创建工厂。我有一种循环的关联,其中一个对象与之后连接在一起的另外两个对象相关联。

+--------------+           +-------------+
|              |           |             |
| TestCase     +---------> | TestDataGrid|
|              |           |             |
+------+-------+           +------+------+
       |                          |
       |                          |
       |                          |
       v                          v
+--------------+           +--------------+
|              |           |              |
|              |           |              |
| TestVariable |           | TestDataSet  |
|              |           |              |
+------+-------+           +------+-------+
       |                          |
       |                          |
       |                          |
       |                          |
       |     +---------------+    |
       |     |               |    |
       |     |               |    |
       +---> | TestDataValue |<---+
             |               |
             +---------------+

class TestCase < ActiveRecord::Base
  has_many :test_variables, dependent: :destroy
  has_many :test_data_grids
  #...omitted code...
end

class TestVariable < ActiveRecord::Base
  belongs_to :test_case
  has_many :test_data_values
  #...omitted code...
end

class TestDataValue < ActiveRecord::Base
  belongs_to :test_variable
  belongs_to :test_data_set
  #...omitted code...
end

class TestDataSet < ActiveRecord::Base
  belongs_to :test_data_grid
  has_many :test_data_values
  #...omitted code...
end

class TestDataGrid < ActiveRecord::Base
  belongs_to :test_case
  has_many :test_data_sets
  #...omitted code...
end

基本上,关联在TestCase中拆分并在TestDataValue中再次连接,我怎样才能创建一个打开和关闭具有相同对象的圆的工厂?

3 个答案:

答案 0 :(得分:0)

这未经过测试,但是:

FactoryGirl.define do

 factory :test_data_value do
  test_data_set
  test_variable
  # attributes
 end

 factory :test_data_set do
  test_data_grid
  # attributes
 end

 factory :test_variable do
  test_case
  # attributes
 end

 factory :test_case do
  # attributes
 end

 factory :test_data_grid do
  test_case
  # attributes
 end
end

然后在规格中:

@test_data_value = FactoryGirl.create(:test_data_value)

@test_variable = @test_data_value.test_variable
@test_data_set = @test_data_value.test_data_set

答案 1 :(得分:0)

我的建议是不要在工厂设置,而是在测试中设置。

工厂文件(感谢@ veritas1)

FactoryGirl.define do

  factory :test_data_value do
    # attributes
  end

  factory :test_data_set do
    # attributes
  end

  factory :test_variable do
    # attributes
  end

  factory :test_case do
    # attributes
  end

  factory :test_data_grid do
    # attributes
  end
end

测试文件

@test_case = FactoryGirl.create(:test_case)
@test_data_grid = FactoryGirl.create(:test_case)
@test_variable = FactoryGirl.create(:test_case)
@test_data_set = FactoryGirl.create(:test_case)
@test_data_value = FactoryGirl.create(:test_case)
@test_case.test_data_grids << @test_data_grid
@test_case.test_variables << @test_variable
@test_data_grid.test_data_set << @test_data_set
@test_variable.test_data_values << @test_data_value
@test_data_set.test_data_values << @test_data_value

我知道它可能会吸一点,但这听起来像是这样做的。但是,如果你正在努力进行测试,那通常就是一个标志,你将在轨道上挣扎,你应该重新设计API。我无法看到另一种方法,但您可以了解域名。

答案 2 :(得分:0)

您可以手动执行此操作:

test_case = FactoryGirl.build(:test_case)

test = FactoryGirl.build(:test_data_value,
  :test_variable => FactoryGirl.build(:test_variable,
     :test_case => test_case
  ),
  :test_data_set => FactoryGirl.build(:test_data_set,
    :test_data_grid => FactoryGirl.build(:test_data_grid,
       :test_case => test_case
    )
  )
)

test.test_variable.test_case == test.test_data_set.test_data_grid.test_case
# => true

或者写一些帮手工厂:

FactoryGirl.define do
  factory :test_data_value do
    ignore do
      test_case nil
      test_data_grid nil
    end

    test_variable do
      build :test_variable,
        :test_case => test_case 
                      || test_data_grid.try(:test_case) 
                      || build(:test_case)
    end

    test_data_set do
      build :test_data_set, :test_data_grid => test_data_grid || (
        build :test_data_grid, :test_case => test_case || build(:test_case)
      )
    end
  end
end

测试用例作为共同祖先:

test = FactoryGirl.create :test_data_value, 
  :test_case => FactoryGirl.build(:test_case)

test.test_variable.test_case == test.test_data_set.test_data_grid.test_case
# => true

作为共同祖先的测试用例和每个实例的相同test_data_grid:

test_data_grid = FactoryGirl.build :test_data_grid, 
  :test_case => FactoryGirl.build(:test_case)

test = FactoryGirl.create :test_data_value, 
  :test_data_grid => test_data_grid

test.test_variable.test_case == test.test_data_set.test_data_grid.test_case
# => true