RSpec
02 / 02

Doubles, Stubs, Spies & the Rails Ecosystem

Doubles, Stubs, Spies & the Rails Ecosystem

Doubles & Verifying Doubles

user_double = double('User', name: 'Ada')

# verifying double — checks the stubbed method actually exists on User
user_double = instance_double(User, name: 'Ada')

allow(repo).to receive(:find).and_return(user_double)
expect(mailer).to receive(:send_welcome).with(user_double)

A plain double happily stubs a nonexistent method; instance_double catches that mismatch immediately — a real safety net when the real class's interface changes.

allow + have_received (Spy Pattern)

allow(mailer).to receive(:send_welcome)

user.register!

expect(mailer).to have_received(:send_welcome).with(user)
# assert AFTER the action — reads more naturally as Arrange/Act/Assert
# than expect().to receive() set up BEFORE the action runs

Shared Examples

RSpec.shared_examples 'a queryable resource' do
  it 'responds to #find' do
    expect(subject).to respond_to(:find)
  end
end

RSpec.describe UserRepository do
  it_behaves_like 'a queryable resource'
end

Avoids duplicating the same behavioral-contract examples across multiple classes that should all satisfy the same interface.

The Rails Testing Stack

RSpec is Rails-agnostic but dominant in the Rails community, typically paired with rspec-rails (controller/model/request test helpers), FactoryBot (test data generation), and often Capybara for feature tests. RSpec's DSL-heavy expressiveness trades some directness for readability compared to Minitest's simpler assert_equal style.

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free