I have a simple question asking Ruby script:
def ask question
while true
puts question
reply = gets.chomp.downcase
return true if reply == 'yes'
return false if reply == 'no'
puts 'Please answer "yes" or "no".'
end
end
puts(ask('Do you like eating tacos?'))
I'm testing it like this
describe 'ask' do
before do
stub(:puts).with('anything')
stub(:puts).with('Please answer "yes" or "no".')
stub(:gets).and_return 'yes'
end
it 'returns true when you say yes' do
expect(ask('anything')).to be true
end
it 'returns false when you say no' do
stub(:gets).and_return 'no'
expect(ask('anything')).to be false
end
end
I had previously been trying to use RSpec 3 syntax with code like
allow(STDIN).to receive(:gets).and_return 'yes'
allow(Kernel).to receive(:gets).and_return 'yes'
allow(IO).to receive(:gets).and_return 'yes'
and other variations but none of these worked, just giving me errors like:
undefined method `chomp' for nil:NilClass
I had better luck with the RSpec 2 syntax, so I enabled that and got the above working, almost. The problem is the line: puts(ask('Do you like eating tacos?'))
. If that is commented out, all is fine, however with it present I was getting this error:
Errno::ENOENT:
No such file or directory @ rb_sysopen
and then now
undefined method
chomp' for nil:NilClass`
So it seems I can stub 'gets' in a method that's called from RSpec, but not if a method using it is called from the ruby file that RSpec is testing.
Any ideas?
Aha, I think I found the solution!
The trick appears to be
allow_any_instance_of(Kernel).to receive(:gets).and_return 'yes'
and calling that in a before block before the application code is pulled in - like so: