ruby - tutorial - ¿Cómo ''espero'' algo que provoque una excepción en RSpec?
rspec test example (4)
Tengo un método que realiza algunas acciones en el modelo de Cat y en el caso de una entrada incorrecta se genera una excepción:
context "hungry cat" do
it { expect { eat(what: nil) }.to raise_error }
end
Lo que quiero hacer es verificar si este método cambia el estado de los gatos, así:
context "hungry cat" do
it { expect { eat(what: nil) }.to raise_error }
it { expect { eat(what: nil) }.not_to change(cat, :status) }
end
El problema es que, como eat(what: nil)
generará una excepción, la segunda fallará sin importar qué. Entonces, ¿es posible ignorar la excepción y verificar alguna condición?
Sé que es posible hacer algo como:
it do
expect do
begin
eat(what: nil)
rescue
end
end.not_to change(cat, :status)
end
Pero es demasiado feo.
Suena extraño que el código eat(what: nil)
no se ejecute de forma aislada para cada una de sus pruebas y afecte a las demás. No estoy seguro, pero quizás reescribir las pruebas levemente resolverá el problema o identificará con más precisión dónde está el problema (seleccione su sabor a continuación).
El uso should
:
context "hungry cat" do
context "when not given anything to eat" do
subject { -> { eat(what: nil) } }
it { should raise_error }
it { should_not change(cat, :status) }
end
end
Usando expect
:
context "hungry cat" do
context "when not given anything to eat" do
let(:eating_nothing) { -> { eat(what: nil) } }
it "raises an error" do
expect(eating_nothing).to raise_error
end
it "doesn''t change cat''s status" do
expect(eating_nothing).to_not change(cat, :status)
end
end
end
Puede usar el modismo "rescatar nada" para acortar lo que ya tiene:
it { expect { eat(what: nil) rescue nil }.not_to change(cat, :status) }
En RSpec 3 puede encadenar las dos pruebas en una sola. Encuentro esto más legible que el enfoque de rescue nil
.
it { expect { eat(what: nil) }.to raise_error.and not_to change(cat, :status)}
Puede encadenar afirmaciones positivas con and
. Si desea mezclar uno negado en la cadena, RSpec 3.1 introdujo define_negated_matcher
.
Podrías hacer algo como:
RSpec::Matchers.define_negated_matcher :avoid_changing, :change
expect { eat(what: nil) }
.to raise_error
.and avoid_changing(cat, :status)
Inspirado por este comentario .