You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用shoulda-matchers的validate_inclusion_of测试抛出ArgumentError求助

问题分析与解决

为什么测试会失败?

这不是预期行为,问题核心是ActiveRecord Enum的自动校验逻辑和shoulda-matchers的测试流程冲突:

  • ActiveRecord的enum会在属性赋值阶段就做校验,只要传入的不是enum定义的键(fir/sec),直接抛出ArgumentError,完全轮不到你手动添加的inclusion验证执行。
  • shoulda-matchers的validate_inclusion_of matcher逻辑是:给属性设置一个不在允许列表的随机字符串(即错误中的'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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:19:56