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

Rspec中expect_to_receive未识别方法调用问题排查

测试方法调用验证失败的原因与解决方案

核心问题

测试中设置调用期望的对象实例,和实际代码执行时调用的不是同一个实例。

原因分析

你的测试代码执行expect(Payments.paymentProviderFactory.provider).to receive(:debit).once时,Payments.paymentProviderFactory.provider返回了一个实例A;当subject.call执行时,Payments.paymentProviderFactory.provider又生成并返回了一个新的实例B。你给实例A设置了调用期望,但实际执行debit的是实例B,所以测试框架统计到实例A的debit调用次数为0。

解决方案

1. 确保Provider是单例实例

如果业务上paymentProviderFactory.provider应该返回同一个实例,修改Factory的provider方法,加入实例缓存:

class Payments::PaymentProviderFactory
  def provider
    # 第一次调用创建实例,后续调用返回缓存的实例
    @provider ||= Payments::CardPaymentProvider.new
  end
end

2. 测试中存根Provider实例

在测试里提前创建一个固定实例,让Factory的provider方法始终返回这个实例,再对它设置期望:

let(:payment_provider) { Payments::CardPaymentProvider.new }

before do
  # 存根Factory,让它每次都返回同一个实例
  allow(Payments.paymentProviderFactory).to receive(:provider).and_return(payment_provider)
end

it "triggers the debit method" do
  expect(payment_provider).to receive(:debit).once
  subject.call
end

3. 验证任意实例的方法调用(不推荐)

如果不需要关注具体实例,只是想确认debit方法被执行过,可以用expect_any_instance_of:

it "calls debit on any CardPaymentProvider instance" do
  expect_any_instance_of(Payments::CardPaymentProvider).to receive(:debit).once
  subject.call
end

注意:这种方式不推荐,因为它会匹配该类的所有实例,可能掩盖代码中的实例创建逻辑问题。

为什么断点能看到方法被调用?

因为实际确实有CardPaymentProvider实例执行了debit方法,但这个实例和你测试中设置期望的实例不是同一个,所以测试框架没有统计到这次调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:39:58