Factory Girl 自连接抛出验证错误
Factory Girl self-join throwing validation errors
我正在尝试测试一个用于创建文章翻译的系统,其中在出版物上有一个自连接 table。我创建了一个工厂,它将创建多个翻译并将它们与 'parent' 文章相关联。
将 Rails 5 与 factory_girl 4.7.0、rspec 和 Database_cleaner
一起使用
所有操作都按预期工作,但问题在于创建测试
这里是相关的模型验证和方法:
# models/publication.rb
has_many :translations, class_name: "Publication", foreign_key: "translation_id", dependent: :nullify
belongs_to :translation, class_name: "Publication", optional: true
validates :language, uniqueness: { scope: :translation_id }, if: :is_translation?
def is_translation?
!translation.nil?
end
工厂(省略无关代码):
# spec/factories/publication.rb
factory :publication, aliases: [:published_pub] do
title 'Default Title'
language 'EN'
published
after(:build) do |object|
create(:version, publication: object)
end
#-- This is where I suspect the problem stems from
trait :with_translations do
association :user, factory: :random_user
after(:build) do |object|
create_list(:translation, 3, {user: object.user, translation:object})
end
end
end
factory :translation, class: Publication do
sequence(:title) { |n| ['French Article', 'Spanish Article', 'German Article', 'Chinese Article'][n]}
sequence(:language) { |n| ['FR', 'ES', 'DE', 'CN'][n]}
user
end
还有一个基本测试:
# spec/models/publication_spec.rb
before(:each) do
@translation_parent = create(:publication, :with_translations)
@pub_without_trans = create(:publication, :with_random_user)
end
scenario 'is_translation?' do
# No actual test code needed, this passes regardless
end
scenario 'has_translations?' do
# No actual test code needed, this (and subsequent tests) fail regardless
end
最后报错:
Failure/Error: create_list(:translation, 3, {user: object.user, translation:object})
ActiveRecord::RecordInvalid:
Validation failed: Language has already been taken
第一个测试通过(并且正确创建了带有翻译的发布对象)但是任何后续测试都失败了。问题是我有一个范围为 translation_id 的唯一性验证,而且 factorygirl 似乎正在尝试将生成的翻译添加到已经存在的出版物中,而不是创建一个全新的出版物。
感谢任何帮助!
已解决!
问题是 translation
工厂中的序列迭代器在每次测试后都没有重置为 0。所以在测试 1 之后,它开始尝试访问一个不存在的数组索引。再次执行此操作后,它触发了验证并且测试失败了!
解决方案不可爱,但暂时够用了
sequence(:language) do |iteration|
array = ['FR', 'ES', 'DE', 'CN']
# Returns a number between 0 and array.length
array[iteration%array.length]
end
sequence(:title) do |iteration|
array = ['French Article', 'Spanish Article', 'German Article', 'Chinese Article']
# Returns a number between 0 and array.length
array[iteration%array.length]
end
我正在尝试测试一个用于创建文章翻译的系统,其中在出版物上有一个自连接 table。我创建了一个工厂,它将创建多个翻译并将它们与 'parent' 文章相关联。
将 Rails 5 与 factory_girl 4.7.0、rspec 和 Database_cleaner
一起使用所有操作都按预期工作,但问题在于创建测试
这里是相关的模型验证和方法:
# models/publication.rb
has_many :translations, class_name: "Publication", foreign_key: "translation_id", dependent: :nullify
belongs_to :translation, class_name: "Publication", optional: true
validates :language, uniqueness: { scope: :translation_id }, if: :is_translation?
def is_translation?
!translation.nil?
end
工厂(省略无关代码):
# spec/factories/publication.rb
factory :publication, aliases: [:published_pub] do
title 'Default Title'
language 'EN'
published
after(:build) do |object|
create(:version, publication: object)
end
#-- This is where I suspect the problem stems from
trait :with_translations do
association :user, factory: :random_user
after(:build) do |object|
create_list(:translation, 3, {user: object.user, translation:object})
end
end
end
factory :translation, class: Publication do
sequence(:title) { |n| ['French Article', 'Spanish Article', 'German Article', 'Chinese Article'][n]}
sequence(:language) { |n| ['FR', 'ES', 'DE', 'CN'][n]}
user
end
还有一个基本测试:
# spec/models/publication_spec.rb
before(:each) do
@translation_parent = create(:publication, :with_translations)
@pub_without_trans = create(:publication, :with_random_user)
end
scenario 'is_translation?' do
# No actual test code needed, this passes regardless
end
scenario 'has_translations?' do
# No actual test code needed, this (and subsequent tests) fail regardless
end
最后报错:
Failure/Error: create_list(:translation, 3, {user: object.user, translation:object})
ActiveRecord::RecordInvalid:
Validation failed: Language has already been taken
第一个测试通过(并且正确创建了带有翻译的发布对象)但是任何后续测试都失败了。问题是我有一个范围为 translation_id 的唯一性验证,而且 factorygirl 似乎正在尝试将生成的翻译添加到已经存在的出版物中,而不是创建一个全新的出版物。
感谢任何帮助!
已解决!
问题是 translation
工厂中的序列迭代器在每次测试后都没有重置为 0。所以在测试 1 之后,它开始尝试访问一个不存在的数组索引。再次执行此操作后,它触发了验证并且测试失败了!
解决方案不可爱,但暂时够用了
sequence(:language) do |iteration|
array = ['FR', 'ES', 'DE', 'CN']
# Returns a number between 0 and array.length
array[iteration%array.length]
end
sequence(:title) do |iteration|
array = ['French Article', 'Spanish Article', 'German Article', 'Chinese Article']
# Returns a number between 0 and array.length
array[iteration%array.length]
end