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

RSpec中如何按对象身份校验have_received方法的调用参数?

根本原因

该问题由 Ruby Comparable 模块特性与 RSpec 参数匹配默认规则共同触发:

  1. 类混入Comparable模块后,Ruby 会自动基于实现的<=>方法生成默认==相等判断逻辑:只要两个实例的<=>返回0,==就返回true,因此示例中val相等的两个不同B类实例b1 == b2结果为true。
  2. RSpec 的with参数匹配器默认使用==做相等校验,因此会把两次传入val相等的B实例的调用都判定为匹配,导致调用计数为2,不符合预期的1次,测试报错。
解决方案

方案1:使用RSpec身份匹配器(推荐,无需修改业务代码)

如果测试需要严格匹配同一个对象实例,不需要改动业务逻辑,只需将with的参数替换为equal匹配器即可。equal基于object_id判断是否为同一实例,不受自定义==方法影响:

# 修改后的测试代码
expect(s).to have_received(:call).with(equal(b1)).exactly(1).times
expect(s).to have_received(:call).with(equal(b2)).exactly(1).times

也可以用功能完全一致的be匹配器代替,写法为with(be(b1))。

方案2:重写类的==方法(仅当业务逻辑需要区分实例相等时使用)

如果业务场景下,即使val相同,不同的B实例也应该判定为不相等,可以显式重写B类的==方法,覆盖Comparable生成的默认逻辑:

class B
  include Comparable
  attr_reader :val

  def initialize(val)
    @val = val
  end

  def <=>(other)
    self.val <=> other.val
  end

  # 显式重写==,要求必须是同一个实例才相等
  def ==(other)
    self.object_id == other.object_id
  end
end

修改后原有测试代码无需改动即可正常运行。


内容的提问来源于stack exchange,提问作者Lam Phan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:45:03