web-dev-qa-db-ja.com

RSpecで終了と中止を検証するにはどうすればよいですか?

すべての検証に合格するように、スクリプトが受け取るコマンドライン引数の動作を指定しようとしています。コマンドライン引数の一部では、指定されたパラメーターが欠落しているか正しくないため、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クラスで使用されています)。

44
cfeduke

これを試して:

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
26
Markus Strauss

答えてくれてありがとう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
17
Greg

新しい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_stdoutRSpecを使用したコマンドラインへの出力のテストのように定義されています。

更新:capture_stdoutの代わりに RSpecのoutputマッチャー の使用を検討してください

15
Dennis

カスタムマッチャーやレスキューブロックは必要ありません。単純に:

expect { exit 1 }.to raise_error(SystemExit) do |error|
  expect(error.status).to eq(1)
end

明示的でプレーンなRspecなので、これは優れていると思います。

5
thisismydesign

それはきれいではありませんが、私はこれを使用しています:

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
4
Kris

掘った後、 私はこれを見つけました

私のソリューションは次のようになりました:

# 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
2
cfeduke

新しい構文要件のため、@ 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
1
David Nedrow