Reputation: 407
I'm writing RSpec unit tests for a CommandLineInterface
class that I've created for my Directory
object. The CommandLineInterface
class uses this Directory
object to print out a list of people in my Directory
. Directory
has a #sort_by(param)
method that returns an array of strings. The order of the strings depends on the param
passed to the #sort_by
method (e.g., sort_by("gender")
. What would be the correct way to mock out this Directory
behavior in my CLI specs? Would I use an instance_double? I am not sure how to do this for a method that takes parameters, like sorting by gender.
I'm only using Ruby and RSpec. No Rails, ActiveRecord, etc. being used here.
Snippets from the class and method I want to mock out:
class Directory
def initialize(params)
#
end
def sort_by(param)
case param
when "gender" then @people.sort_by(&:gender)
when "name" then @people.sort_by(&:name)
else raise ArgumentError
end
end
end
Upvotes: 1
Views: 4406
Reputation: 4555
It all depends on how your objects are collaborating.
Some information is lacking in your question:
CommandLineInterface
use Directory
? Does it create an instance by itself or does it receive one as an argument?Here's how you could do it if you pass in the dependent object:
require 'rspec/autorun'
class A
def initialize(b)
@b = b
end
def foo(thing)
@b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:b) { double('an instance of B') }
let(:a) { A.new(b) }
it 'calls b.bar with qux' do
expect(b).to receive(:bar).with('qux')
a.foo('qux')
end
end
end
end
If the class initializes the dependant object and it isn't important to know which instance got the message you can do this:
require 'rspec/autorun'
B = Class.new
class A
def initialize
@b = B.new
end
def foo(thing)
@b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:a) { A.new }
it 'calls b.bar with qux' do
expect_any_instance_of(B).to receive(:bar).with('qux')
a.foo('qux')
end
end
end
end
If you just want to stub out the return value and not test whether the exact message was received, you can use allow
:
require 'rspec/autorun'
B = Class.new
class A
def initialize
@b = B.new
end
def foo(thing)
thing + @b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:a) { A.new }
it 'returns qux and b.bar' do
allow_any_instance_of(B).to receive(:bar).with('qux') { 'jabber' }
expect(a.foo('qux')).to eq('quxjabber')
end
end
end
end
Upvotes: 2