如何在RSpec中验证退出和中止?

cfe*_*uke 42 ruby rspec mocking

我正在尝试为脚本接收的命令行参数指定行为,以确保所有验证都通过.我的一些命令行参数将导致abort或被exit调用,因为提供的参数缺失或不正确.

我正在尝试这样不起作用的东西:

# 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
Run Code Online (Sandbox Code Playgroud)

exit方法干净利落地阻止RSpec验证测试(我得到"SystemExit:exit").

我也尝试过,mock(Kernel)但是这也没有按照我的意愿工作(我没有看到任何明显的区别,但这可能是因为我不确定如何模拟内核并确保在我的内核中使用了模拟的内核Something类).

Mar*_*uss 26

试试这个:

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
Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 17

谢谢你回答马库斯.一旦我有了这个线索,我就可以把一个好的匹配器放在一起以备将来使用.

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
Run Code Online (Sandbox Code Playgroud)

要使用此匹配器,请将其添加到库或规范助手中:

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
Run Code Online (Sandbox Code Playgroud)


Den*_*nis 15

使用新的RSpec语法:

expect { code_that_exits }.to raise_error(SystemExit)
Run Code Online (Sandbox Code Playgroud)

如果某些内容被打印到STDOUT并且您想要测试它,您可以执行以下操作:

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
Run Code Online (Sandbox Code Playgroud)

其中capture_stdout定义为在使用RSpec的测试输出到命令行中看到的位置 .

更新:考虑使用RSpec的output匹配器代替capture_stdout

  • 还有一个内置的`output`匹配器:https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher (4认同)

thi*_*ign 10

不需要自定义匹配器或救援块,只需:

expect { exit 1 }.to raise_error(SystemExit) do |error|
  expect(error.status).to eq(1)
end
Run Code Online (Sandbox Code Playgroud)

我认为这是优越的,因为它是明确而简单的 Rspec。