我如何validationRSpec中的退出和中止?

我正在尝试规范我的脚本收到的命令行参数的行为,以确保所有的validation通过。 我的一些命令行参数会导致abortexit被调用,因为提供的参数丢失或不正确。

我正在尝试这样的不工作:

 # something_spec.rb require 'something' describe Something do before do Kernel.stub!(:exit) end it "should exit cleanly when -h is used" do s = Something.new Kernel.should_receive(:exit) s.process_arguments(["-h"]) end end 

exit方法是干净地射击防止RSpecvalidationtesting(我得到“SystemExit:退出”)。

我也试图mock(Kernel)但也没有工作,因为我想(我没有看到任何可辨别的差异,但这可能是因为我不知道如何嘲笑内核,并确保嘲笑的内核在我的Something类中使用)。

尝试这个:

 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 end end 

感谢Markus的回答。 一旦我有这个线索,我可以把一个不错的匹配器,以备将来使用。

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

要使用这个匹配器,将它添加到您的库或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})" end end 

使用新的RSpec语法:

 expect { code_that_exits }.to raise_error(SystemExit) 

如果某些内容打印到标准输出,并且您也想testing,则可以执行如下操作:

 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) end end 

其中capture_stdout的定义如在testing输出到RSpec的命令行中所见。

更新:考虑使用RSpec的output匹配器而不是capture_stdout

它不漂亮,但我一直在使用这个:

 begin do_something rescue SystemExit => e expect(e.status).to eq 1 # exited with failure status # or expect(e.status).to eq 0 # exited with success status else expect(true).eq false # this should never happen end 

挖完之后, 我发现了这个 。

我的解决scheme看起来像这样:

 # something.rb class Something def initialize(kernel=Kernel) @kernel = kernel end def process_arguments(args) @kernel.exit end end # something_spec.rb require 'something' describe Something do before :each do @mock_kernel = mock(Kernel) @mock_kernel.stub!(:exit) end it "should exit cleanly" do s = Something.new(@mock_kernel) @mock_kernel.should_receive(:exit) s.process_arguments(["-h"]) end end 

由于新的语法要求,我不得不更新@Greg提供的解决scheme。

 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 do |block| "expected block to call exit(#{exp_code}) but exit" + (actual.nil? ? " not called" : "(#{actual}) was called") end failure_message_when_negated do |block| "expected block not to call exit(#{exp_code})" end description do "expect block to call exit(#{exp_code})" end supports_block_expectations end