2009-09-26 1 views
36

모든 유효성 검사가 통과하도록하기 위해 스크립트가받는 명령 줄 인수에 대한 동작을 지정하려고합니다. 내 명령 줄 인수 중 일부는 제공된 매개 변수가 없거나 올바르지 않기 때문에 abort 또는 exit이 호출됩니다.RSpec에서 종료 및 중단을 검증하려면 어떻게해야합니까?

I가 작동하지 않는이 같은 노력하고 있어요 :

# 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없이"나는 얻을).

나는 또한 mock(Kernel)으로 시도했지만 그 역시 내가 원하는대로 작동하지 않습니다. (나는 눈에 띄는 차이는 보이지 않지만, 정확히 어떻게 커널을 조롱하고 잘 조롱했는지 확신 할 수 없기 때문일 수 있습니다. 커널은 내 Something 클래스에서 사용됩니다.

답변

25

이 시도 : 대답 마르쿠스에 대한

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 
+0

경고 : RSpec에이 아마도'exit's이 기대가 실패 할 때, 그래서 우리는 우리 자신의 등 대신에 RSpec에의'exit's를 구출 끝낼 수 있기 때문에 우리는 유사한 솔루션으로 문제가 있었다 –

2

파기 후, I found this.

# 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 
16

감사를

내 솔루션은 다음과 같이 찾고 끝났다. 이 실마리가 생기면 나중에 사용할 멋진 matcher를 만들 수 있습니다.

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 
3

그것의 꽤하지,하지만 난이 사용하고있다 :이 정규 표현을 사용하려면

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 

은 라이브러리 나 사양 - 헬퍼이 추가 새로운 사용

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 
12

을 RSpec 구문 :

expect { code_that_exits }.to raise_error(SystemExit) 

som 당신이 뭔가를 할 수 ething는 STDOUT에 인쇄하고 당신도 그것을 테스트 할 :

Test output to command line with RSpec에서 볼 수 있듯이 capture_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 

.

업데이트 : 나는 새로운 구문 요구 사항으로 인해 제공되는 솔루션 @Greg를 업데이트했다 RSpec's output matcher 대신

+4

도 있습니다 내장 'output' matcher : https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher –

+0

@JaredBeck이 의견을 보내 주셔서 감사합니다. 나는 최근에 RSpec의'output_to_stdout_from_any_process' matcher를 사용하여 시스템 명령의 출력을 캡처했습니다. 디스크 I/O로 인해 속도가 느려지더라도 제대로 작동했습니다. – Dennis

1

capture_stdout의 사용하는 것이 좋습니다.

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 
관련 문제