2009-09-26 13 views
36

Próbuję określić zachowania dla argumentów wiersza poleceń otrzymanych przez mój skrypt, aby upewnić się, że wszystkie sprawdzania poprawności mija. Niektóre z moich argumentów wiersza poleceń powodują wywołanie abort lub exit, ponieważ podane parametry są nieprawidłowe lub niepoprawne.Jak mogę sprawdzić poprawność wyjść i przerw w RSpec?

próbuję czegoś takiego, który nie działa:

# 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 

Sposób exit jest wypalania czysto zapobiegając rspec od ważności badania (mam „SystemExit: exit”).

Próbowałem też mock(Kernel), ale to też nie działa tak jakbym chciał (nie widzę żadnej zauważalnej różnicy, ale to prawdopodobnie dlatego, że nie jestem pewien, jak dokładnie kpić z Kernela i zadbać o wyśmiewanie się Kernel jest używany w mojej klasie Something).

Odpowiedz

25

spróbuj tego:

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

Ostrzeżenie: Mieliśmy problemy z podobnym rozwiązaniem, ponieważ RSpec przypuszczalnie 'exit's gdy oczekiwania nie, więc może skończyć ratowania' exit's RSpec zamiast naszego własnego itp –

2

Po kopaniu, I found this.

Moje rozwiązanie skończyło się patrząc tak:

# 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

Dzięki za odpowiedź Markus. Gdy już miałem tę wskazówkę, mogłem połączyć ładne urządzenie do przyszłego użytku.

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 

Aby skorzystać z tej dopasowywania dodać to do swoich bibliotek lub Spec-pomocników:

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

Jej nie całkiem, ale używam tego:

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

Korzystanie nowa Składnia RSpec:

expect { code_that_exits }.to raise_error(SystemExit) 

Jeśli som ething jest drukowana na standardowe wyjście i chcesz sprawdzić, czy też można zrobić coś takiego:

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 

Gdzie capture_stdout jest zdefiniowany jak widać w Test output to command line with RSpec.

Aktualizacja: Rozważ użycie RSpec's output matcher zamiast capture_stdout

+4

Jest też wbudowany 'output' matcher: https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher –

+0

@JaredBeck dzięki za komentarz. Ostatnio użyłem narzędzia RSpec 'output_to_stdout_from_any_process' matcher do przechwytywania danych wyjściowych polecenia systemowego i chociaż jest wolne z powodu operacji we/wy dysku, działało dobrze. – Dennis

1

musiałem zaktualizować rozwiązanie @Greg dostarczone z powodu nowych wymagań składniowych.

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 
Powiązane problemy