Damian Damian - 5 months ago 36
Ruby Question

How to stub/mock multiple options depending on user input with Rspec 3.4

I am completely new to Rspec, and it's my first time trying to test outside of the rails framework. I am simply trying to understand how I can possibly mock behavior of my app when the implementation is pretty complex.

I want to be able to mimic the behavior of calling

customize_gender
inputting a choice and checking that when 1 is entered the result is 'Male', when 2 is entered the result is 'Female', etc.

I also want to be able to check if the instance variable of
@gender
was correctly set, which is why I added the
attr_reader :gender
in the first place. I have been trying a few things, but I guess I do not understand how mocks in general work to be able to find a solution. I have looked at similar questions but they do not seem to work for my scenario. Any insight is greatly appreciated!

Main file (person.rb)


class Person
attr_reader :gender

GENDER = { male: 'Male', female: 'Female', other: 'Other'}

def initialize
puts customize_gender
end

def customize_gender
display_hash_option GENDER, 'What is your gender? '
choice = gets.chomp.to_i
@gender =
case choice
when 1
GENDER[:male]
when 2
GENDER[:female]
when 3
print 'Enter your preferred gender: '
gets.chomp.downcase
else
puts 'Error: Person -> customize_gender()'
end
end

private

def display_hash_option(hash, saying = '')
print saying
hash.each_with_index { |(key, _value), index| print "#{index.next}) #{key} " }
end

end


Rspec File (spec/person_spec.rb)


require_relative "../person"
describe Person do
let(:person) { Person.new }
allow(Person).to receive(:gets).and_return(1,2,3)
person.customize_gender
expect(person.gender).to eq 'Male'
# allow(person).to receive(:customize_gender).and_return('Male')
# expect(Person).to receive(:puts).with('What is your gender?')
# allow(Person).to receive(:gets) { 1 }
# expect(person.gender).to eq 'Male'
end

Answer

Here's how you could do it, the only thing mocked here is that gets is set to '1' (remember it's a string in this case as gets input is always a string)

RSpec.describe Person do
  subject { Person.new }

  it 'returns male as gender when male is chosen' do
    allow(subject).to receive(:gets).and_return('1')
    subject.customize_gender

    expect(subject.gender).to eq('Male')
  end
end

For when 3 you could use the following.

RSpec.describe Person do
  subject { Person.new }

  it 'returns other as gender when other has been entered' do
    allow(subject).to receive(:gets).and_return('3', 'other')
    subject.customize_gender

    expect(subject.gender).to eq('other')
  end
end
Comments