Testing setters with RSpec, should_receive, and create?
I'm working on an e-commerce system and familiarizing myself with RSpec.
An order has an associated payment. When the order is completed it starts to process the payment via our payment gateway.
Below is the spec, the a开发者_Go百科ppropriate method, and the failure message.
require 'spec_helper'
describe Order, "#process_payment" do
let!(:user) { create_user }
let!(:credit_card) { new_credit_card }
let!(:order) { user.orders.create! total: 200 }
let!(:payment) { stub('payment', started_processing!: true, ) }
before do
credit_card.stub(sale: true)
order.stub(credit_card: credit_card)
order.payments.stub(create!: payment)
payment.stub(:source= => true, process!: true)
end
it "creates a payment" do
order.payments.should_receive(:create!).
with(amount: 200, source: credit_card).and_return payment
order.process_payment
end
it "sets the payment's source to the credit card and tells it to process!" do
payment.should_receive(:source=).with(credit_card).ordered
payment.should_receive(:process!).ordered
order.process_payment
end
end
Here is the Order class.
class Order < ActiveRecord::Base
...
def process_payment
payments.create!(amount: total, source: credit_card).tap do |payment|
payment.process!
end
end
...
end
The second spec is failing, claiming that :source= is never received. With ordered, it just says that process! is called out of order. Without ordered, it says that it expected :source= once, but never received it. I understand why ordered should be there, but just wanted to be clear that it is claiming that :source= is never being received.
Is create! not calling source=? What is the appropriate way to test to make sure the source is being set on the payment correctly?
I would say that your it "creates a payment"
spec is enough. The responsibility for the behavior of create!
should be in a spec written specifically for it.
If you really want to make sure create!
is doing what it's supposed to, perhaps try letting process_payment
save to the database then call Payment.last
to get the new record and check the properties on it. But I think that would be overkill.
Think of it this way, when you write controller specs you don't test all the behavior of your models again; you just test how your controller interfaces with them. This is a similar situation.
精彩评论