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