Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/44.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何在RSpec中验证退出和中止?_Ruby_Rspec_Mocking - Fatal编程技术网

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

Ruby 如何在RSpec中验证退出和中止?,ruby,rspec,mocking,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

我试图为脚本接收的命令行参数指定行为,以确保所有验证都通过。我的一些命令行参数将导致调用
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
exit
方法正在干净地启动,阻止RSpec验证测试(我得到“SystemExit:exit”)

我也尝试过
模拟(内核)
,但这也不是我想要的(我看不到任何明显的区别,但这可能是因为我不确定如何精确地模拟内核,并确保模拟的内核在我的
Something
类中使用)。

挖掘之后

我的解决方案最终是这样的:

# 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
试试这个:

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

谢谢你的回答,马库斯。一旦我有了这个线索,我就可以组装一个很好的匹配器,以备将来使用

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
要使用此匹配器,请将其添加到库或等级库帮助器中:

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

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

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

使用新的RSpec语法:

expect { code_that_exits }.to raise_error(SystemExit)
如果将某些内容打印到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
context“使用-h或--help选项时”do
它可以“打印帮助并退出”吗
帮助=%Q(
用法:my_应用程序[选项]
-h、 --帮助显示此帮助消息
)

ARGV由于新的语法要求,我不得不更新@Greg提供的解决方案

RSpec::Matchers.define:exit_with_code do | exp_code|
实际值=零
匹配do |块|
开始
阻塞呼叫
救援系统出口=>e
实际=e.状态
结束
实际值和实际值==exp\u代码
结束
故障|信息do |块|
“预期块调用exit(#{exp_code}),但退出”+
(actual.nil???“未调用”:“(#{actual})已调用”)
结束
当_否定do |块时失败_消息|
“预期块不调用出口(#{exp_code})”
结束
描述
“期望块调用exit(#{exp_code})”
结束
支持\u块\u期望值
结束

无需定制匹配器或救援块,只需:

expect { exit 1 }.to raise_error(SystemExit) do |error|
  expect(error.status).to eq(1)
end
我认为这是优越的,因为它是显式和简单的Rspec。

只是查找命令的退出状态代码。 如果您所做的只是测试命令的退出状态代码,则可以执行以下操作:

# 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
描述你要做的事情
它“应该无错误地退出”吗
预期(系统(“将退出且状态代码为零”)。为真
结束
它“应该以错误退出”吗
预期(系统(“将退出且状态代码为非零”)。为false
结束
结束
这是因为
系统将返回:

  • true
    当命令以“0”状态代码退出时(即无错误)
  • false
    当命令以非0状态代码(即错误)退出时
如果要从rspec文档输出中禁用
系统
命令的输出,可以按如下方式重定向:

system(“will_exit_,状态为0_code)”,[:out,:err]=>File::NULL)

我已经使用@Greg的解决方案很多年了,但是我已经修改了它以与rspec3+一起使用

我还对其进行了调整,使代码现在可以选择性地检查退出状态,我发现这更加灵活

用法 来源
RSpec::Matchers.define:call\u exit do
实际状态=零
匹配do |块|
开始
阻塞呼叫
救援系统出口=>e
实际状态=e状态
结束
实际_状态&(预期_状态.nil?| |实际_状态==预期_状态)
结束
链:具有,:预期的\u状态
def支持_block_期望值?
真的
结束
故障|信息do |块|
预期='退出'
预期+=“(#{预期_状态})”如果预期_状态
实际值=零
实际=“退出(#{actual_status})”如果为实际_状态
“应为块调用`#{应为}`but”+
(actual.nil???'从未调用exit':“{actual}`被调用”)
结束
当_否定do |块时失败_消息|
预期='退出'
预期+=“(#{预期_状态})”如果预期_状态
“预期块不调用`{expected}`”
结束
描述
预期='退出'
预期+=“(#{预期_状态})”如果预期_状态
“期望块调用`{expected}`”
结束
结束

警告:我们在使用类似的解决方案时遇到了问题,因为当预期失败时,RSpec可能会退出
s,因此我们最终可能会拯救RSpec的退出
s,而不是我们自己的退出等。还有一个内置的输出匹配器:@JaredBeck感谢您的评论。我最近使用RSpec的
output\u-to\u-stdout\u-from\u-any\u进程
matcher来捕获系统命令的输出,尽管由于磁盘I/O的原因,它的速度很慢,但它工作得很好。