पाठ 20 / 25
Testing with RSpec and Minitest
Write tests with RSpec and Minitest, including doubles.
A strong testing culture
Ruby has a strong testing culture, and two frameworks dominate. Minitest ships with Ruby and is used by Rails by default: test classes subclass Minitest::Test, methods start with test_, and assertions such as assert_equal(expected, actual) and assert_raises check behaviour; it also offers a spec style. RSpec provides a readable DSL: describe and context group examples, it defines them, expect(actual).to eq(expected) asserts with matchers (be_truthy, include, raise_error, change { ... }.by(1), have_attributes), and let defines lazily evaluated helpers. Both support test doubles: RSpec's instance_double(PaymentGateway, charge: "pay_1") creates verified doubles that fail if you stub methods the real class does not have, and expect(gateway).to receive(:charge).with(...) checks interactions. Use FactoryBot for test data, WebMock or VCR to stub HTTP, and SimpleCov for coverage. Run tests on every change in CI, and keep them fast by isolating I/O.
The same behaviour tested with RSpec and Minitest
Verified doubles catch stubs of methods that do not exist.
# spec/checkout_spec.rb (RSpec)
RSpec.describe Checkout do
let(:gateway) { instance_double(PaymentGateway, charge: "pay_1") }
subject(:checkout) { described_class.new(gateway) }
it "charges the order total once" do
expect(checkout.pay(order_id: "o-1", amount_paise: 49_900)).to eq("pay_1")
expect(gateway).to have_received(:charge).with("o-1", 49_900).once
end
it "rejects non-positive amounts" do
expect { checkout.pay(order_id: "o-2", amount_paise: 0) }.to raise_error(ArgumentError)
end
end
# test/checkout_test.rb (Minitest)
require "minitest/autorun"
class CheckoutTest < Minitest::Test
FakeGateway = Struct.new(:calls) do
def charge(order_id, amount) = (calls << [order_id, amount]; "pay_1")
end
def test_charges_once
gateway = FakeGateway.new([])
assert_equal "pay_1", Checkout.new(gateway).pay(order_id: "o-1", amount_paise: 49_900)
assert_equal [["o-1", 49_900]], gateway.calls
end
endTwo languages, one meaning
RSpec and Minitest are like writing the same rule in two styles: one as a sentence ("it charges the order once"), the other as a plain checklist. Both prove the same thing; teams choose the style they read best.
त्वरित जाँच: What does RSpec's instance_double provide over a plain double?
- Faster tests
- Database access
- Automatic test data
- Verification that stubbed methods actually exist on the real class with matching arguments
Answer
Verification that stubbed methods actually exist on the real class with matching arguments — Verified doubles fail when you stub methods the real class does not define.