ruby - practices - Rspec: espera frente a espera con bloque, ¿cuál es la diferencia?
rspec capybara best practices (2)
Como se ha mencionado:
expect(4).to eq(4)
Esto es específicamente probar el valor que ha enviado como parámetro al método. Cuando intentas probar errores planteados cuando haces lo mismo:
expect(raise "fail!").to raise_error
Su argumento se evalúa de inmediato y esa excepción se lanzará y su prueba explotará allí mismo.
Sin embargo, cuando usa un bloque (y esto es ruby básico), el contenido del bloque no se ejecuta inmediatamente; su ejecución está determinada por el método que está llamando (en este caso, el método de expect
controla cuándo ejecutar su bloque) :
expect{raise "fail!"}.to raise_error
Podemos ver un método de ejemplo que podría manejar este comportamiento:
def expect(val=nil)
if block_given?
begin
yield
rescue
puts "Your block raised an error!"
end
else
puts "The value under test is #{val}"
end
end
Aquí puede ver que es el método de expect
que está rescatando manualmente su error para que pueda probar si los errores se yield
o no, etc. el yield
es la forma en que un método ruby de ejecutar cualquier bloque se le pasó al método.
Simplemente aprendiendo la sintaxis de rspec y noté que este código funciona:
context "given a bad list of players" do
let(:bad_players) { {} }
it "fails to create given a bad player list" do
expect{ Team.new("Random", bad_players) }.to raise_error
end
end
Pero este código no lo hace:
context "given a bad list of players" do
let(:bad_players) { {} }
it "fails to create given a bad player list" do
expect( Team.new("Random", bad_players) ).to raise_error
end
end
Me da este error:
Team given a bad list of players fails to create given a bad player list
Failure/Error: expect( Team.new("Random", bad_players) ).to raise_error
Exception:
Exception
# ./lib/team.rb:6:in `initialize''
# ./spec/team_spec.rb:23:in `new''
# ./spec/team_spec.rb:23:in `block (3 levels) in <top (required)>''
Mi pregunta es:
- ¿Por qué pasó esto?
- ¿Cuál es la diferencia entre el ejemplo anterior y el anterior exactamente en ruby?
También estoy buscando reglas sobre cuándo usar una sobre la otra.
Un ejemplo más de los mismos resultados, pero inversos, donde funciona este código:
it "has a list of players" do
expect(Team.new("Random").players).to be_kind_of Array
end
Pero este código falla
it "has a list of players" do
expect{ Team.new("Random").players }.to be_kind_of Array
end
El error que recibo en este caso es:
Failure/Error: expect{ Team.new("Random").players }.to be_kind_of Array
expected #<Proc:0x007fbbbab29580@/Users/amiterandole/Documents/current/ruby_sandbox/tdd-ruby/spec/team_spec.rb:9> to be a kind of Array
# ./spec/team_spec.rb:9:in `block (2 levels) in <top (required)>''
La clase que estoy probando se ve así:
class Team
attr_reader :name, :players
def initialize(name, players = [])
raise Exception unless players.is_a? Array
@name = name
@players = players
end
end
En el primer caso, cuando pasa un bloque a expect
, la ejecución del bloque no se produce hasta que llega el momento de evaluar el resultado, momento en el que el código RSpec puede detectar cualquier error que se genere y compararlo con la expectativa.
En el segundo caso, el error surge cuando se evalúa el argumento a expect
, por lo expect
código de expect
no tiene oportunidad de involucrarse.
En cuanto a las reglas, pasa un bloque o un Proc
si está tratando de probar el comportamiento (por ejemplo, aumentar errores, cambiar algún valor). De lo contrario, pasa un argumento "convencional", en cuyo caso el valor de ese argumento es lo que se prueba.