すべての検証に合格するように、スクリプトが受け取るコマンドライン引数の動作を指定しようとしています。コマンドライン引数の一部では、指定されたパラメーターが欠落しているか正しくないため、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」が表示されます)。
私も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
このマッチャーを使用するには、これをライブラリまたはスペックヘルパーに追加します。
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)
何かが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
ここで、capture_stdout
はRSpecを使用したコマンドラインへの出力のテストのように定義されています。
更新:capture_stdout
の代わりに RSpecのoutput
マッチャー の使用を検討してください
カスタムマッチャーやレスキューブロックは必要ありません。単純に:
expect { exit 1 }.to raise_error(SystemExit) do |error|
expect(error.status).to eq(1)
end
明示的でプレーンなRspecなので、これは優れていると思います。
それはきれいではありませんが、私はこれを使用しています:
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
掘った後、 私はこれを見つけました 。
私のソリューションは次のようになりました:
# 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が提供するソリューションを更新する必要がありました。
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