Reputation: 3723
I am writing a command line interface to a Ruby gem and I have this method exit_error
, which acts as an exit error point to all validations performed while processing.
def self.exit_error(code,possibilities=[])
puts @errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
where @errormsgs
is a hash whose keys are the error codes and whose values are the corresponding error messages.
This way I may give users customized error messages writing validations like:
exit_error(101,@commands) if not valid_command? command
where:
@errormsgs[101] => "Invalid command."
@commands = [ :create, :remove, :list ]
and the user typing a wrong command would receive an error message like:
Invalid command.
It should be:
create
remove
list
At the same time, this way I may have bash scripts detecting exactly the error code who caused the exit condition, and this is very important to my gem.
Everything is working fine with this method and this strategy as a whole. But I must confess that I wrote all this without writing tests first. I know, I know... Shame on me!
Now that I am done with the gem, I want to improve my code coverage rate. Everything else was done by the book, writing tests first and code after tests. So, it would be great having tests for these error conditions too.
It happens that I really don't know how to write Rspec tests to this particular situation, when I use exit
to interrupt processing. Any suggestions?
Update => This gem is part of a "programming environment" full of bash scripts. Some of these scripts need to know exactly the error condition which interrupted the execution of a command to act accordingly.
Upvotes: 1
Views: 673
Reputation: 16002
For example:
class MyClass
def self.exit_error(code,possibilities=[])
puts @errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
end
You could write its rspec to be something like this:
describe 'exit_error' do
let(:errormsgs) { {101: "Invalid command."} }
let(:commands) { [ :create, :remove, :list ] }
context 'exit with success'
before(:each) do
MyClass.errormsgs = errormsgs # example/assuming that you can @errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(true)
end
it 'should print commands of failures'
expect(MyClass).to receive(:puts).with(errormsgs[101])
expect(MyClass).to receive(:puts).with("It should be:")
expect(MyClass).to receive(:puts).with(" create")
expect(MyClass).to receive(:puts).with(" remove")
expect(MyClass).to receive(:puts).with(" list")
MyClass.exit_error(101, commands)
end
end
context 'exit with failure'
before(:each) do
MyClass.errormsgs = {} # example/assuming that you can @errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(false)
end
# follow the same approach as above for a failure
end
end
Of course this is an initial premise for your specs and might not just work if you copy and paste the code. You will have to do a bit of a reading and refactoring in order to get green signals from rspec.
Upvotes: 2