How can I validate exits and aborts in RSpec? How can I validate exits and aborts in RSpec? ruby ruby

How can I validate exits and aborts in RSpec?


try this:

module MyGem  describe "CLI" do    context "execute" do      it "should exit cleanly when -h is used" do        argv=["-h"]        out = StringIO.new        lambda { ::MyGem::CLI.execute( out, argv) }.should raise_error SystemExit      end    end  endend


Using the new RSpec syntax:

expect { code_that_exits }.to raise_error(SystemExit)

If something is printed to STDOUT and you want to test that too, you can do something like:

context "when -h or --help option used" do  it "prints the help and exits" do    help = %Q(      Usage: my_app [options]        -h, --help                       Shows this help message    )    ARGV << "-h"    expect do      output = capture_stdout { my_app.execute(ARGV) }      expect(output).to eq(help)    end.to raise_error(SystemExit)    ARGV << "--help"    expect do      output = capture_stdout { my_app.execute(ARGV) }      expect(output).to eq(help)    end.to raise_error(SystemExit)  endend

Where capture_stdout is defined as seen in Test output to command line with RSpec.

Update: Consider using RSpec's output matcher instead of capture_stdout


Thanks for the answer Markus. Once I had this clue I could put together a nice matcher for future use.

it "should exit cleanly when -h is used" do  lambda { ::MyGem::CLI.execute( StringIO.new, ["-h"]) }.should exit_with_code(0)endit "should exit with error on unknown option" do  lambda { ::MyGem::CLI.execute( StringIO.new, ["--bad-option"]) }.should exit_with_code(-1)end

To use this matcher add this to your libraries or spec-helpers:

RSpec::Matchers.define :exit_with_code do |exp_code|  actual = nil  match do |block|    begin      block.call    rescue SystemExit => e      actual = e.status    end    actual and actual == exp_code  end  failure_message_for_should do |block|    "expected block to call exit(#{exp_code}) but exit" +      (actual.nil? ? " not called" : "(#{actual}) was called")  end  failure_message_for_should_not do |block|    "expected block not to call exit(#{exp_code})"  end  description do    "expect block to call exit(#{exp_code})"  endend