RSpec Mocks
Remarks#
This topic documents RSpec’s support for test doubles (stubs, mocks, etc.). That support is provided by the rspec-mocks gem.
Stubbing with allow
The following example uses allow
and receive
to stub a Cart
’s call to a CreditCardService
so that the example doesn’t have to wait for a network call or use a credit card number that the processor knows about.
class Cart
def check_out
begin
transaction_id = CreditCardService.instance.validate credit_card_number, total_price
order = Order.new
order.items = cart.items
order
rescue CreditCardService::ValidationFailedError
# handle the error
end
end
end
describe Cart do
describe '#check_out' do
it "places an order" do
allow(CreditCardService.instance).
to receive(:validate).with("1234567812345678", 3700).and_return("transaction_id")
cart = Cart.new
cart.items << Item.new("Propeller beanie", 3700)
order = cart.check_out
expect(order.transaction_id).to eq("transaction_id")
end
end
end
with
is optional; without it, any arguments are accepted. and_return
is optional too; without it the stub returns nil
.
Mocking by setting a message expectation with expect
The following example uses expect
and receive
to mock an Order
’s call to a CreditCardService
, so that the test passes only if the call is made without having to actually make it.
class Order
def cancel
CreditCardService.instance.refund transaction_id
end
end
describe Order do
describe '#cancel' do
it "refunds the money" do
order = Order.new
order.transaction_id = "transaction_id"
expect(CreditCardService.instance).to receive(:refund).with("transaction_id")
order.cancel
end
end
end
In this example the mock is on the return value of CreditCardService.instance
, which is presumably a singleton.
with
is optional; without it, any call to refund
would satisfy the expectation. A return value could be given with and_return
; in this example it is not used, so the call returns nil
.