我的User
模型的子关联为items
。 :name
项应该对用户来说是唯一的,但它应该允许不同的用户拥有一个具有相同名称的项目。
项目模型目前设置为:
class Item < ApplicationRecord
belongs_to :user
validates :name, case_sensitive: false, uniqueness: { scope: :user }
end
这可用于验证用户内部,但仍允许其他用户保存具有相同名称的项目。
如何使用RSpec / Shoulda进行测试?
我目前的测试写成:
describe 'validations' do
it { should validate_uniqueness_of(:name).case_insensitive.scoped_to(:user) }
end
但是这个测试失败是因为:
Failure/Error: it { should validate_uniqueness_of(:name).scoped_to(:user).case_insensitive }
Item did not properly validate that :name is case-insensitively
unique within the scope of :user.
After taking the given Item, setting its :name to ‹"an
arbitrary value"›, and saving it as the existing record, then making a
new Item and setting its :name to a different value, ‹"AN
ARBITRARY VALUE"› and its :user to a different value, ‹nil›, the
matcher expected the new Item to be invalid, but it was valid
instead.
然而,这是我想要的行为(除了为用户选择nil
的奇怪部分)。当用户不同时,相同的名称应该有效。
我可能没有正确使用范围测试,或者使用Shoulda这是不可能的,这里是the description of scoped tests。在这种情况下,您将如何编写模型测试来测试此行为?
答案 0 :(得分:1)
这样做的解决方案有三个方面:
范围为:user_id
而不是模型中的:user
在模型上重写验证,将所有唯一性要求作为哈希的一部分包含
:user_id
问题中的代码将起作用,它正确地检查不区分大小写的唯一性,但最好将所有唯一性要求包括为散列,因为the docs中的示例即使对于单个声明也采用此形式(另外,这是我能找到的唯一方法,让Shoulda测试通过正确的行为)。
这就是工作代码的样子:
模型
class Item < ApplicationRecord
belongs_to :user
validates :name, uniqueness: { scope: :user_id, case_sensitive: false }
end
测试
RSpec.describe Item, type: :model do
describe 'validations' do
it { should validate_uniqueness_of(:name).scoped_to(:user_id).case_insensitive }
end
end
答案 1 :(得分:0)
我尝试过enum
模型
validates(:plan_type,
uniqueness: { scope: :benefit_class_id, case_sensitive: false })
enum plan_type: {
rrsp: 0,
dpsp: 1,
tfsa: 2,
nrsp: 3,
rpp: 4,
}
测试
it { should validate_uniqueness_of(:plan_type).scoped_to(:benefit_class_id).case_insensitive }
但总是出现类型错误(即enum
值在测试中为大写)
1) BenefitClass::RetirementPlan validations should validate that :plan_type is case-insensitively unique within the scope of :benefit_class_id
Failure/Error:
is_expected.to validate_uniqueness_of(:plan_type)
.scoped_to(:benefit_class_id).case_insensitive
ArgumentError:
'RPP' is not a valid plan_type
但是我能够编写通过的显式测试。
it 'validates uniqueness of plan_type scoped to benefit_class_id' do
rp1 = FactoryBot.create(:retirement_plan)
rp2 = FactoryBot.build(
:retirement_plan,
benefit_class_id: rp1.benefit_class_id,
plan_type: rp1.plan_type,
)
expect(rp2).to_not be_valid
end