ruby - run - rspec spectroscopy
¿Hay una alternativa menos intrusiva al `should_receive` de Rspec? (3)
Al escribir pruebas de Rspec, a menudo me siento frustrado con should_receive
. Me gustaría saber si hay una alternativa menos intrusiva.
Por ejemplo:
describe "making a cake" do
it "should use some other methods" do
@baker.should_receive(:make_batter)
@baker.make_cake
end
end
La llamada a should_receive
es una buena descripción, pero rompe mi código, porque should_receive
enmascara el método original y make_cake
no puede continuar a menos que make_batter
devuelva algo de batter. Entonces lo cambio a esto:
@baker.should_receive(:make_batter).and_return(@batter)
Esto es feo porque:
- Parece que estoy probando que
make_batter
devuelvemake_batter
correctamente, pero en realidad estoy forzando a la versión falsa demake_batter
a devolver eso. - Me obliga a configurar por separado
@batter
- Si
make_batter
tiene algún efecto secundario importante (que podría ser un olor a código, supongo) también tengo que hacer que eso suceda.
Me gustaría que should_receive(:make_batter)
verificara la llamada al método y la pasara al método original . Si quisiera mostrar su comportamiento para una mejor prueba de aislamiento, lo haría explícitamente: @baker.stub(:make_batter).and_return(@batter)
.
¿Hay alguna manera de hacer algo como should_receive
sin evitar la llamada al método original? ¿Mi problema es un síntoma de mal diseño?
Estás teniendo este problema con should_receive
porque estás probando los detalles de implementación del método make_cake
. Al escribir pruebas, solo debe enfocarse en el comportamiento y no en una secuencia de llamadas a métodos internos. De lo contrario, la refacturación posterior de su código generaría una refacturación enorme de todas sus pruebas.
Los simulacros y los talones son útiles cuando quieres probar tus clases de forma aislada. Al escribir pruebas unitarias, el sujeto de prueba debe aislarse de cualquier otro objeto. Ambos actúan como un sustituto cuando trabajas con múltiples objetos a la vez. En este caso, puede usar should_receive
para asegurarse de que su sujeto de prueba delegue correctamente una tarea en otro objeto llamando a un método.
Parece que la mejor API para delegar en el método original al que aludió Myron Marston se ha agregado realmente en rspec-mocks v2.12.0
Así que ahora puede simplemente hacer esto cada vez que "quiera establecer una expectativa de mensaje sin interferir con la forma en que el objeto responde al mensaje":
@baker.should_receive(:make_batter).and_call_original
Gracias por agregar esto, Myron.
Puede tener should_receive
ejecutar el método original de esta manera:
@baker.should_receive(:make_batter, &@baker.method(:make_batter))
Tanto el should_receive
como el de stub
pasan una implementación de bloque (que se evalúa cuando se llama al método). &@baker.method(:make_batter)
maneja el objeto del método original y lo pasa como la implementación del bloque.
FWIW, nos gustaría proporcionar una mejor API para delegar en el método original (ver este problema ), pero es difícil agregar esa funcionalidad sin romper la compatibilidad hacia atrás.