Mocking Stripe::Charge - RSpec 说它没有实现 :retrieve

Tho*_*kke 3 ruby unit-testing rspec ruby-on-rails

我试图Stripe::Charge.retrieve在我的一些测试中模拟,但出现错误:

Failure/Error: allow_any_instance_of(Stripe::Charge).to receive(:retrieve)
       Stripe::Charge does not implement #retrieve
Run Code Online (Sandbox Code Playgroud)

我猜 Stripe API 做了某种反射来生成这个方法。有没有办法模拟这个方法?或者也许是一种关闭 RSpec 功能的方法,该功能验证特定测试是否存在模拟方法?

Ale*_*x P 6

Stripe::Charge.retrieve是一个类方法,但您试图像实例方法一样模拟它。这里最大的提示是该方法称为“检索” - 您正在尝试获取一个Stripe::Charge对象,而在 Ruby 中使用类方法来实现这一点更为惯用。Rspec 的错误不是很有用;如果它说“实例Stripe::Charge不实现#retrieve”会更准确。

好消息是你可以在 Rspec 中非常简单地模拟这个:

allow(Stripe::Charge).to receive(:retrieve)
Run Code Online (Sandbox Code Playgroud)

这里有一个简短的例子来演示这一点,取自一个包含 Stripe gem 和 rspec-rails 的 Rails 项目。首先,一个大部分为空的支付模型:

class Payment < ActiveRecord::Base
  def get_stripe_charge(payment_ref)
    Stripe::Charge.retrieve(payment_ref)
  end
end
Run Code Online (Sandbox Code Playgroud)

现在spec/models/payment_spec.rb来演示模拟:

require 'rails_helper'

RSpec.describe Payment, type: :model do
  it "Allows retrieval of a payment" do
    allow(Stripe::Charge).to receive(:retrieve).and_return("Avocados") # A mock object would be more useful here.

    payment = Payment.new
    expect(payment.get_stripe_charge("whatever")).to eql("Avocados")
  end
end
Run Code Online (Sandbox Code Playgroud)