allow ruby rspec mocking

ruby - allow - ¿Cómo puedo validar las salidas y cancelaciones en RSpec?



rspec allow (7)

Después de excavar, encontré esto .

Mi solución terminó luciendo así:

# 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

Estoy tratando de especificar comportamientos para los argumentos de línea de comandos que recibe mi script para garantizar que todas las validaciones pasen. Algunos de mis argumentos de la línea de comandos darán como resultado la abort o la invocación de la exit porque los parámetros suministrados faltan o son incorrectos.

Estoy intentando algo como esto que no funciona:

# 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

El método de exit se activa limpiamente impidiendo que RSpec valide la prueba (obtengo "SystemExit: exit").

También traté de mock(Kernel) pero eso tampoco funciona como me gustaría (no veo ninguna diferencia discernible, pero es probable porque no estoy seguro de cómo burlarse de Kernel y asegurarme de que el Kernel se burló se usa en mi clase de Something ).


Gracias por la respuesta Markus. Una vez que tuve esta pista, pude armar un buen comparador para 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

Para usar este matcher, agregue esto a sus bibliotecas o ayudantes de especificación:

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


No es bonito, pero he estado usando esto:

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


No hay necesidad de emparejadores personalizados o bloques de rescate, simplemente:

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

Yo diría que esto es superior porque es Rspec explícito y simple.


Tuve que actualizar la solución @Greg proporcionada debido a los nuevos requisitos de sintaxis.

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


Usando la nueva sintaxis de RSpec:

expect { code_that_exits }.to raise_error(SystemExit)

Si se imprime algo en STDOUT y desea probarlo también, puede hacer algo como:

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

Donde capture_stdout se define como se ve en Prueba de salida a la línea de comando con RSpec .

Actualización: considere usar el matcher de output RSpec en lugar de capture_stdout


prueba esto:

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