Rspec: 如何测试引发错误的方法

Rspec: How to test a method that raises an error

我有一个 SubscriptionHandler class,它的调用方法可以创建待定订阅,尝试向用户收费,然后在收费失败时出错。无论计费是否失败,都会创建待定订阅

class SubscriptionHandler

  def initialize(customer, stripe_token)
    @customer = customer
    @stripe_token = stripe_token
  end

  def call
    create_pending_subscription
    attempt_charge!
    upgrade_subscription
  end

  private

  attr_reader :stripe_token, :customer

  def create_pending_subscription
   @subscription = Subscription.create(pending: true, customer_id: customer.id)
  end

  def attempt_charge!
    StripeCharger.new(stripe_token).charge!  #raises FailedPaymentError
  end

  def upgrade_subscription
   @subscription.update(pending: true)
  end

 end

这是我的规格:

describe SubscriptionHandler do

  describe "#call" do
    it "creates a pending subscription" do
      customer = create(:customer)
      token = "token-xxx"
      charger = StripeCharger.new(token)
      allow(StripeCharger).to receive(:new).and_return(charger)
      allow(charger).to receive(:charge!).and_raise(FailedPaymentError)
      handler = SubscriptionHandler.new(customer, token)

      expect { handler.call }.to change { Subscription.count }.by(1) # Fails with FailedPaymentError
    end
  end
end

但这不会更改订阅计数,它会因 FailedPaymentError 而失败。有没有一种方法可以检查订阅计数是否增加,而规范不会因 FailedPaymentError 而崩溃。

可以这样做

expect{ handler.call }.to raise_error FailedPaymentError

应该可以。

如果您根本不想引发错误,那么您可以删除此行,并 return 一个有效的响应

allow(charger).to receive(:charge!).and_raise(FailedPaymentError)

更多信息 - How to test exception raising in Rails/RSpec?

官方RSpec文档

https://relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-error

您应该能够对此使用 Rspec 复合期望

https://relishapp.com/rspec/rspec-expectations/docs/compound-expectations

所以我会把你的期望重写成这样:

expect { handler.call }.
 to raise_error(FailedPaymentError).
 and change { Subscription.count }.by(1)