Writing a Rspec test for an error condition finished with exit

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

Answers (1)

Surya
Surya

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

Related Questions