How can I validate exits and aborts in RSpec?
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