tests spectroscopy run rails how example better ruby rspec

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 devuelve make_batter correctamente, pero en realidad estoy forzando a la versión falsa de make_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.