FactoryGirl创建重复实例

时间:2016-01-30 22:42:09

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

我想测试city模型上条目的唯一性。

class City < ActiveRecord::Base
  validates :name, uniqueness: { scope: :country_code,
    message: "This city has already been added" }
end

我需要创建一个用于测试此验证的规范。我的想法是测试将遵循这些方针:

my_city = FactoryGirl.create(:city)

context "when inserting" do
  it "cannot have the same name and country code" do
    expect{create :my_city}.to raise_error(ActiveRecord::DuplicateRecord)
  end
end

但是,我一直无法弄清楚如何使用FactoryGirl创建my_city对象的重复实例。只需使用上面代码段中演示的create :my_city即可:

ArgumentError: Factory not registered: my_city

修改

这是City工厂的样子:

# spec/factories/city_factory.rb
FactoryGirl.define do
  factory :city do
    name { Faker::Address.city}
    country { CountryCodes.find(Faker::Address.country_code)}
    latitude { Faker::Number.decimal(2, 6)}
    longitude { Faker::Number.decimal(2, 6)}
    population { Faker::Number.number([3, 6, 7].sample) }
    timezone { Faker::Address.time_zone }
  end
end

两次运行create :city这么简单,会导致插入两个完全不同的城市。我需要两次测试同一个城市。

4 个答案:

答案 0 :(得分:2)

您可以像这样测试验证:

RSpec.describe City do
  let(:city) { create :city }
  subject    { city }

  it { should validate_uniqueness_of(:name).scoped_to(:country_code) }
end

但首先你需要为这样的城市建立你的工厂(在一个单独的文件上):

FactoryGirl.define do
  factory :city do
    sequence(:name) { |n| Faker::Lorem.word + "(#{n})" }
  end
end

答案 1 :(得分:2)

通常,测试唯一性非常简单。让shoulda匹配器为您完成工作。一旦你有工厂,你就可以做到这一点......

specify { 
  create :city; 
  is_expected.to validate_uniqueness_of(:name).scoped_to(:country_code) }

您必须至少创建一条记录。然后,shoulda匹配器将使用该记录,读取其属性,并制作副本以测试您的验证。

答案 2 :(得分:1)

好吧,我不能用错误告诉你的更好的词语。您没有注册my_city的工厂。如果您想创建重复记录,只需调用create方法两次,然后传递您要测试的重复属性。例如,您可以通过以下方式测试:

it "cannot have the same name and country code" do
  first_city = create :city
  duplicate_city = build(:city, name: first_city.name, country_code: first_city.country_code)
  expect(duplicate_city).not_to be_valid
end


it "cannot have the same name and country code" do
  attrs = FactoryGirl.attributes_for :city
  first_city = create :city, attrs
  duplicate_city = build(:city, attrs)
  expect(duplicate_city).not_to be_valid
end


it "cannot have the same name and country code" do
  first_city = create :city
  expect{create (:city, name: first_city.name, country_code: first_city.country_code)}.to raise_error(ActiveRecord::DuplicateRecord)
end

请注意,每次调用create方法时,您都在创建一条新记录,因此第二次调用它时,数据库中已存在现有记录,唯一不同的属性是id。例外情况是,如果您在工厂中声明了sequence或其他一些方法调用,这些调用将在测试执行时发生变化,例如Date.today

答案 3 :(得分:1)

如果您不想使用shoulda-matchers,只需使用FactoryGirl创建第一个城市,然后使用相同的name和{{1 }}。最后,测试检查有效性时产生的错误消息:

country_code