Rspec模拟初始化时哈希被识别为关键字参数的问题解决
Rails 7.1.3升级后RSpec Mock位置哈希参数被识别为关键字参数的解决方法
问题场景
升级至Rails 7.1.3后,定义的类初始化方法同时包含带默认空哈希的位置参数和关键字参数:
def initialize(opts = {}, foo: :bar)
在RSpec测试中Mock该初始化方法时,传入哈希作为位置参数:
options = {cow: "over", moon: "under"} expect(Thing).to(receive(:new).with(options))
触发错误:RSpec::Mocks::MockExpectationError: Invalid keyword arguments provided: cow, moon,哈希被错误识别为关键字参数。
已尝试的无效方案:
- 将哈希存入变量后传递给
with方法 - 在
with和new调用中添加关键字参数 - 移除默认空哈希参数(可通过测试但不符合业务需求)
解决方法
方法1:使用精确匹配器明确指定位置参数
通过eq()匹配器告诉RSpec,第一个参数是完全匹配的哈希:
expect(Thing).to receive(:new).with(eq(options))
如果只需要验证哈希包含指定键值对,可改用hash_including():
expect(Thing).to receive(:new).with(hash_including(cow: "over"))
方法2:通过块验证参数类型与内容
使用块接收调用时的参数,手动验证位置参数和关键字参数:
expect(Thing).to receive(:new) do |opts, **kwargs| expect(opts).to eq(options) expect(kwargs).to be_empty # 根据实际需求验证关键字参数 end
方法3:指定参数类型匹配器
如果只需要验证第一个参数是哈希类型,可使用instance_of(Hash):
expect(Thing).to receive(:new).with(instance_of(Hash))
可复现最小代码
class Thing def initialize(opts = {}, foo: "bar") end end require "rspec" describe Thing do let(:options) { {cow: "over", moon: "below"} } it "mocks out the initialize" do # 替换为上述解决方法中的expect语句即可通过测试 expect(Thing).to receive(:new).with(eq(options)) Thing.new(options) end end
相关Gem版本
rails (7.1.3) rspec (3.13.0) rspec-core (3.13.0) rspec-expectations (3.13.0) rspec-mocks (3.13.0) rspec-rails (6.1.0) rspec-retry (0.6.2) rspec-support (3.13.0)
内容的提问来源于stack exchange,提问作者AJFaraday
相关产品推荐
相关产品推荐

