spectroscopy - Como probar pone en rspec
rspec example (5)
Lo que quiero hacer es ejecutar ruby sayhello.rb
en la línea de comandos, luego recibir Hello from Rspec
.
Lo tengo con esto:
class Hello
def speak
puts ''Hello from RSpec''
end
end
hi = Hello.new #brings my object into existence
hi.speak
Ahora quiero escribir una prueba en rspec para verificar que la salida de la línea de comandos sea en realidad "Hola de RSpec" y no "Me gusta Unix"
NO FUNCIONA. Actualmente tengo esto en mi archivo sayhello_spec.rb
require_relative ''sayhello.rb'' #points to file so I can ''see'' it
describe "sayhello.rb" do
it "should say ''Hello from Rspec'' when ran" do
STDOUT.should_receive(:puts).with(''Hello from RSpec'')
end
end
Además, necesito ver cómo se ve la prueba en mi RSPEC, por favor.
Algo similar a la respuesta de bswinnerton, uno puede capturar salidas de prueba y luego compararlas con la salida capturada, sin tener que usar el método de capture
dependiente de la biblioteca (que alguien mencionó está en desuso en Rails 5).
Ruby tiene una variable global llamada $stdout
que, de forma predeterminada, se rellena con la constante STDOUT
. STDOUT
es la que envía datos a la secuencia de salida estándar del proceso ruby (no estoy seguro de que "secuencia" sea el término correcto aquí). Básicamente, en un caso ingenuo, STDOUT.puts("foo")
hará que aparezca "foo / n" en la ventana de su terminal. $stdout.puts("foo")
hará lo mismo porque el nombre de la variable $stdout
se refiere a STDOUT
menos que lo reasigne (punto clave aquí). Finalmente, puts("foo")
es azúcar sintáctica para $stdout.puts("foo")
.
La estrategia entonces es reasignar $stdout
a una instancia de IO
local que pueda inspeccionar después de ejecutar su código, para ver si "Hello from RSpec" apareció en su contenido.
Cómo funcionaría esto:
describe "sayhello.rb" do
it "should say ''Hello from Rspec'' when ran" do
$stdout = StringIO.new
# run the code
# (a little funky; would prefer Hello.new.speak here but only changing one thing at a time)
require_relative ''sayhello.rb''
$stdout.rewind # IOs act like a tape so we gotta rewind before we play it back
expect($stdout.gets.strip).to eq(''Hello from Rspec'')
end
end
Creo que la mejor manera es usar rspec build in output matcher https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher
Por ejemplo, esta es tu clase.
class MakeIt
def awesome(text)
puts "Awesome #{text}"
end
end
y tu prueba
describe MakeIt do
describe ''#awesome'' do
it ''prints awesome things'' do
expect do
MakeIt.new.awesome(''tests'')
end.to output(''Awesome tests'').to_stdout
end
it ''does not print not awesome things'' do
expect do
MakeIt.new.awesome(''tests'')
end.to_not output(''Not awesome tests'').to_stdout
end
end
end
Agradable, limpio y por el libro!
Está ejecutando su código antes de ingresar al bloque de prueba, por lo que no se cumplen las expectativas. Debe ejecutar el código dentro del bloque de prueba después de establecer las expectativas (por ejemplo, moviendo la declaración require_relative
después de la instrucción STDOUT....
), de la siguiente manera:
describe "sayhello.rb" do
it "should say ''Hello from Rspec'' when ran" do
STDOUT.should_receive(:puts).with(''Hello from RSpec'')
require_relative ''sayhello.rb'' #load/run the file
end
end
Puedes resolver esto usando la biblioteca active_support Rails, que agrega un método de capture
:
require ''active_support/core_ext/kernel/reporting''
require_relative ''sayhello''
describe Hello do
it "says ''Hello from RSpec'' when ran" do
output = capture(:stdout) do
hi = Hello.new
hi.speak
end
expect(output).to include ''Hello from RSpec''
end
end
Según las respuestas / comentarios anteriores, una solución que use la nueva sintaxis sin una gema se vería así:
describe "sayhello.rb" do
it "should say ''Hello from Rspec'' when run" do
expect(STDOUT).to receive(:puts).with(''Hello from RSpec'')
require_relative ''sayhello.rb'' # load/run the file
end
end