As far as I understand you want to test exit_or_continue
method depending on user input. In this method, there are two main important things. One of them is the user input that @cli.ask
does and other one is exit
method that quits the program if the user input is quit
.
To test these flow we need to stub both Kernel.exit
and HighLine#ask
method.
Firstly, we override the Kernel.exit
method inside the instance of Asker
class. The Kernel
module is included in the Object
class and every class extend Object
class implicitly in ruby. So our Asker
class has the methods of Kernel
by default.
Why we stub the exit
method inside the instance of Asker
class is this would lead to unexpected problems if we stub it globally(In Kernel). What is more, unless we stub this method rspec quits and the rest of tests are not run.
Secondly, we need to stub HighLine#ask
method which waits for input from the client. HighLine#ask
is method and this uses Kernel.gets
under the hood. By stubbing this method, basically we say 'please return this value and do not wait for user input.'. In other words, with @cli.stub(ask: 'quit')
this will return quit
or whatever you want without prompt something.
So I think the following test will accomplish your need. If you encounter any problem please do not hesitate to drop a comment.
RSpec.describe Asker do
describe '#exit_or_continue' do
before do
@asker = Asker.new
@cli = @asker.instance_variable_get('@cli')
@asker.stub(exit: true) # We override Kernel.exit method inside asker instance
end
context 'when user input is quit' do
it 'returns true' do
@cli.stub(ask: 'quit') # We stub HighLine#ask method to return quit on behalf of the user.
expect(@sker.exit_or_continue).to be(true)
end
end
context 'when user is input is NOT quit' do
it 'returns nil' do
@cli.stub(ask: 'invalid response') # We stub HighLine#ask method to return invalid response on behalf of the user.
expect(@sker.exit_or_continue).to be_nil
end
end
end
end