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的原因,它的速度很慢,但它工作得很好。