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

Want to receive useful tips, information about new Ruby gems and articles on a daily basis? Make sure you follow me and say hello!

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.

Want to become a better Rails developer?
Download for free the Introduction Rails patterns book and dive into the world of refactoring and easy-testable Ruby code today.
Join over 1,000 developers already subscribed to my newsletter and download the book. You can unsubscribe anytime:

Subscribe and get the book!