2009-09-26 15 views
36

Sto provando a specificare i comportamenti per gli argomenti della riga di comando che il mio script riceve per garantire che tutta la validazione passi. Alcuni dei miei argomenti della riga di comando risulteranno invocati in abort o exit perché i parametri forniti sono mancanti o errati.Come posso convalidare uscite e aborti in RSpec?

sto cercando qualcosa di simile che non sta funzionando:

# 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 

Il metodo exit sta sparando in modo pulito impedendo RSpec dal convalidare la prova (ottengo "SystemExit: uscita").

Ho anche provato a mock(Kernel) ma anche questo non funziona come vorrei (non vedo alcuna differenza visibile, ma è probabile perché non sono sicuro di come esattamente deridere il kernel e assicurarsi che il mocked Il kernel viene utilizzato nella mia classe Something).

risposta

25

provare questo:

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

Attenzione: abbiamo avuto problemi con una soluzione simile, perché RSpec presumibilmente 'exit's quando le aspettative non riescono, così abbiamo potuto finire salvataggio' exit's di RSpec invece del nostro ecc –

2

Dopo lo scavo, I found this.

La mia soluzione ha finito per assomigliare a questo:

# 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

Grazie per la risposta Markus. Una volta avuto questo indizio, ho potuto mettere insieme un bel matcher per l'uso futuro.

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 

Per utilizzare questa matcher aggiungere questo alle librerie o Spec-aiutanti:

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

La sua non è abbastanza, ma ho usato questo:

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

Utilizzando il nuovo Sintassi di RSpec:

expect { code_that_exits }.to raise_error(SystemExit) 

Se som ething viene stampato STDOUT e si desidera testare anche quello, si può fare qualcosa di simile:

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 

Dove capture_stdout è definito come visto in Test output to command line with RSpec.

Aggiornamento: Considerare l'utilizzo RSpec's output matcher invece di capture_stdout

+4

C'è anche un built-in 'matcher 'output': https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher –

+0

@JaredBeck grazie per il commento. Recentemente ho usato RSPec come outputer_to_stdout_from_any_process' per l'acquisizione di output di un comando di sistema e sebbene sia lento a causa dell'I/O del disco, ha funzionato bene. – Dennis

1

ho dovuto aggiornare la soluzione @ Greg previsto a causa dei requisiti di sintassi più recenti.

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 
Problemi correlati