Ryan-Neal Mes
Ryan-Neal Mes

Reputation: 6263

How to test service object

I have written the service object below.

class LeadGeneration
  def initialize contact_id
    @lead = Lead.find_or_initialize_by(contact_id: contact_id)
  end

  def lead
    @lead
  end

  def activate_lead
    lead.active!
  end

  def stale_lead
     lead.stale!
  end
end

I am a little confused on how exactly to test it. I have written the spec below

require 'spec_helper'

describe LeadGeneration do
    let(:contact) { FactoryGirl.create(:contact) }

 it "#activate_lead" do
    lg = LeadGeneration.new(contact.id)
    expect(lg.lead).to receive(:active!)
    lg.activate_lead
  end

  it "#stale_lead" do
    lg = LeadGeneration.new(contact.id)
    expect(lg.lead).to receive(:stale!)
    lg.stale_lead
  end
end

This spec works fine, but I would like to do it without exposing the lead that is generated. How exactly do I go about this. I could use

expect(Lead.any_instance).to receive(:active!)

But from my reading this is bad practice. Any thoughts?

Upvotes: 0

Views: 1150

Answers (1)

Sandy W
Sandy W

Reputation: 356

Since in this instance all you're testing is that the lead object receives messages, you can stub #lead to return a mock object that you set expectations on:

it "#activate_lead" do
  lead = double('lead')
  lg = LeadGeneration.new(contact.id)
  # make #lead return our test double whenever it's called
  allow(lg).to receive(:lead) { lead }
  # our test double should receive the message
  expect(lead).to receive(:active!)
  lg.activate_lead
end

This means you could move the #lead method into a private/protected space, since you don't have to call it directly anymore.

Upvotes: 2

Related Questions