2012-09-07 10 views
6

He tenido problemas para crear fábricas para algunos objetos y asociaciones que he definido en mi proyecto. Tengo un tipo de asociación cíclica, donde un objeto se asocia con otros dos objetos que luego se unen.¿Cómo podría crear fábricas para una asociación cíclica en FactoryGirl?

+--------------+   +-------------+ 
|    |   |    | 
| 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 

Básicamente la asociación se divide en TestCase y se une de nuevo en TestDataValue, ¿cómo podría crear una fábrica que se abre y se cierra el círculo con los mismos objetos?

+1

¿Realmente lo necesita? En la mayoría de los casos, puedes burlarte de todas esas relaciones. Es extremadamente difícil mantener fábricas tan complejas. – Sigurd

Respuesta

0

Esto no se ha probado, pero:

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 

Luego, en especificaciones:

@test_data_value = FactoryGirl.create(:test_data_value) 

@test_variable = @test_data_value.test_variable 
@test_data_set = @test_data_value.test_data_set 
+0

el problema con esto sería que: test_variable y: test_data_grid crearía instancias diferentes de a: test_case si no me equivoco, y realmente necesito que este sea el mismo objeto. – bruno077

+0

Tenía preguntas similares de FactoryGirl sobre la configuración de prueba compleja. Lo resolví llamando a ThoughtBot y comprando una hora de su tiempo. Sé que esto es inusual; Lo sugiero aquí porque a) me funcionó, b) está ofreciendo una gran recompensa, así que supongo que quiere una respuesta de alta calidad pronto, yc) está haciendo una buena pregunta sólida. – joelparkerhenderson

0

Mi sugerencia sería que no configurarlo en las fábricas, sino en las propias pruebas.

archivo de fábrica (gracias a @ 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 

Archivo de prueba

@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 

Sé que puede aspirar un poco, pero parece que la manera de hacerlo. Sin embargo, como pensamiento, si estás luchando con tus pruebas, suele ser una señal de que tendrás dificultades con la pista y deberías rediseñar las API. No puedo ver una forma alternativa de hacerlo, pero es posible que pueda hacerlo con el conocimiento del dominio.

+0

Pensando en eso, solo puedes usar devoluciones de llamada. Declare las asociaciones como dijo @ veritas1, pero luego en la fábrica de TestCase, use a después de crear una devolución de llamada para configurar todo lo que describí anteriormente. https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#callbacks – FluffyJack

0

Puede hacerlo de forma manual:

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 

O escribir alguna fábrica ayudante:

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 

caso de prueba antepasado común:

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 

caso de prueba antepasado común y el mismo test_data_grid para cada instancia:

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 
Cuestiones relacionadas