Factory Girl中的重复关联

时间:2016-03-17 16:33:20

标签: ruby-on-rails factory-bot

我正在使用fixture来在Ruby on Rails项目上加载测试数据。我搬到了Factory Girl,但我收到了重复的协会条目。

我有Group模型和Value模型。 Group可以有多个Values

另外,我正在使用Cucumber进行测试。并FactoryGirl.lint填充数据库。

我的灯具

groups.yml

group_1:
  name: "Flavour"

values.yml

value_1:
  name: "Strawberry"
  group: group_1

value_2:
  name: "Mint"
  group: group_1

value_3:
  name: "Chocolate"
  group: group_1

这很好用。创建一个Group并将3 Values附加到其上。

我的工厂

groups.rb

FactoryGirl.define do
  factory :group do
    name "Flavour"
  end
end

values.rb

FactoryGirl.define do
  factory :value_1, class: :value do
    name "Strawberry"
    group
  end

  factory :value_2, class: :value do
    name "Mint"
    group
  end

  factory :value_3, class: :value do
    name "Chocolate"
    group
  end
end

这不起作用。 Factory Girl正在创建3 Groups,每个{1}与1 Value相关联。

这是Factory Girl的正常行为吗?

另外,我读到use_transactional_fixtures应该设置为true。情况已经如此。

2 个答案:

答案 0 :(得分:2)

您的价值工厂被告知要将集团工厂用于他们的集团,并且集团工厂被告知要创建一个名为' Flavor'的新集团。您想要做的不同的是,您希望集团工厂返回现有的' Flavor'而不是一个新的。这是如何做到的。

FactoryGirl.define do
  factory :group, class: :group do
    name 'Flavor'
    initialize_with {Group.find_or_initialize_by(name: name)}
  end
end

即如果您已经拥有所需名称的组,请使用现有组。如上所述,以便有一个默认名称,你得到相同的'使用现有的如果存在'传递替代名称时的行为。

答案 1 :(得分:2)

我不认为你真的已经掌握了使用固定装置和工厂之间的概念差异。

  • 使用fixtures,您可以在每次测试运行时将这些静态对象定义放入数据库中。就像你的数据库有一个"零"已经拥有大量数据的状态。感觉很好,温暖和模糊(哦,我不必把所有东西都设置好,太好了!)但它实际上是一个可怕的想法,因为它掩盖了空桌引起的任何错误!
  • 使用工厂,您可以动态定义对象,并在需要时创建它们。您可以使用database_cleaner之类的工具清除测试之间的任何残留状态。你什么也没做就开始了。

FactoryGirl.lint不会填充数据库。它是一个检查您的工厂定义是否正确的linter。

如果你只是用它创建一堆灯具,那么使用factory_girl绝对没有意义。所以你想要做的事情是:

FactoryGirl.define do
  factory :value do
    name { ["Strawberry", "Mint", "Chocolate"].sample }
    group
  end
end

从固定装置到工厂的一个心理障碍是你必须停止编写测试,就像你在哪里使用夹具数据一样:

describe "GET /users/:id" do

  let!(:user){ FactoryGirl.create(:user) }
  let(:json) { JSON.parse(response.body) }

  before { get users_path(@user), format: :json }

  it "has the correct name" do
    # bad
    expect(json["name"]).to eq "John Doe" # strong coupling to factory!

    # good 
    expect(json["name"]).to eq user.name # we don't know what the factory generates.
  end
end

如果必须进行测试,必须知道某个工厂值,或者工厂需要与某个对象相关联,那么请明确地进行测试,而不要弄乱你的定义。

let(:user) { FactoryGirl.create(:user, name: 'Max') }
let(:item) { user.items.create(FactoryGirl.attributes_for(:item)) }

it "has an awesome name" do
  expect(user.name).to eq 'Max'
end

it "is associated" do
  expect(item.user).to eq user
end
相关问题