使用shoulda-matchers的validate_inclusion_of测试抛出ArgumentError求助
问题分析与解决
为什么测试会失败?
这不是预期行为,问题核心是ActiveRecord Enum的自动校验逻辑和shoulda-matchers的测试流程冲突:
- ActiveRecord的enum会在属性赋值阶段就做校验,只要传入的不是enum定义的键(
fir/sec),直接抛出ArgumentError,完全轮不到你手动添加的inclusion验证执行。 - shoulda-matchers的
validate_inclusion_ofmatcher逻辑是:给属性设置一个不在允许列表的随机字符串(即错误中的'shoulda-matchers test string'),再检查模型是否触发验证错误。但enum在赋值时直接报错,打断了matcher的测试流程,导致测试失败。
可行解决方法
方案1:移除冗余的手动inclusion验证
ActiveRecord的enum已经自带值校验,你手动添加的validates :a_type, inclusion: { in: a_types.keys }是多余的,直接删除即可。如需测试enum的有效值,改用shoulda-matchers专门的enum matcher:
describe 'Validations' do it { is_expected.to validate_presence_of(:a_type) } it { is_expected.to define_enum_for(:a_type).with_values(fir: 'first', sec: 'second') } end
方案2:绕过enum的赋值拦截(保留手动验证时用)
如果一定要保留手动inclusion验证,可以直接操作模型的属性哈希,跳过enum的setter方法:
it 'validates inclusion of a_type' do foo = Foo.new # 直接写入attributes哈希,避开enum的赋值校验 foo.attributes = { a_type: 'invalid_value' } expect(foo).to be_invalid expect(foo.errors[:a_type]).to include('is not included in the list') end
补充说明
validate_inclusion_of matcher是为普通属性设计的,没有考虑到enum会在赋值阶段直接抛出异常的特性,因此出现了这个兼容性问题。使用enum专属的matcher是更贴合Rails特性的做法。
内容的提问来源于stack exchange,提问作者piyush
相关产品推荐
相关产品推荐

