RSpec spies explained

Ruby on Rails / RSpec

RSpec spies are a combination of mocks and stubs. If you are not familiarized with them you can check previous post about this topic: RSpec stubs explained.

You can divide spies into a three-step flow:

  1. Setup – you are using allow to stub your classes and get responses that you want
  2. Exercise – you execute tested method
  3. Verification – you are using expect and have_received to test if your code meet expectations

Let’s see implementation on a sample class.

class UserService
  def initialize(user:, name:)
    @user = user
    @name = name

  def save_name
    name_service = name)
    user.update_attribute(:name, name_service.get_name(format: :short))

  attr_reader :user, :name
require 'spec_helper'

describe UserService do
  describe "#save_name" do
    # Setup
    name_service = instance_double(NameService, get_name: double)
    user = instance_double(User, update_attribute: double)
    short_name = 'Nick'
    name = 'Nick Martin'
    allow(NameService).to receive(:new).with(name: name).and_return(name_service)
    allow(name_service).to receive(:get_name).with(format: :short).and_return(short_name)
    allow(user).to receive(:update_attribute).with(:name, short_name)

    # Exercise
    user_service = user, name: name)

    # Verification
    expect(name_service).to have_received(:get_name).with(format: :short)
    expect(user).to receive(:update_attribute).with(:name, short_name)

Of course, you can do it faster but in using spies it’s all about clarity, especially in more complicated cases, so that’s why we divided the whole test into separated sections.