Existe-t-il une alternative moins intrusive à `should_receive` de Rspec?

En écrivant des tests Rspec, je suis souvent frustré par should_receive . J’aimerais savoir s’il existe une alternative moins intrusive.

Par exemple:

 describe "making a cake" do it "should use some other methods" do @baker.should_receive(:make_batter) @baker.make_cake end end 

L’appel à should_receive est une bonne description, mais il casse mon code, car should_receive fonctionne en masquant la méthode d’origine, et make_cake ne peut pas continuer à moins que make_batter ne retourne effectivement du frappeur. Donc je change ça en:

 @baker.should_receive(:make_batter).and_return(@batter) 

C’est moche parce que:

  • Il semblerait que je teste que make_batter renvoie correctement @batter , mais je force en fait la fausse version de make_batter à la renvoyer.
  • Cela me force à mettre en place @batter
  • Si make_batter a des effets secondaires importants (ce qui pourrait être une odeur de code, je suppose), je dois les faire aussi.

Je souhaite que should_receive(:make_batter) vérifie l’appel de la méthode et le transmette à la méthode d’origine . Si je voulais modifier son comportement pour un meilleur test d’isolement, je le ferais explicitement: @baker.stub(:make_batter).and_return(@batter) .

Est-il possible de faire quelque chose comme should_receive sans empêcher l’appel à la méthode d’origine? Est-ce que mon problème est un symptôme de mauvaise conception?

Il semble que l’API plus agréable à déléguer à la méthode originale à laquelle Myron Marston a fait allusion a été ajoutée dans la version v2.12.0 de rspec-mocks.

  • Ajouter and_call_original qui délègue à la méthode d’origine.

Alors maintenant, vous pouvez simplement le faire à tout moment lorsque vous “souhaitez définir une expecation de message sans interférer avec la façon dont l’object répond au message”:

 @baker.should_receive(:make_batter).and_call_original 

Merci d’avoir ajouté ceci, Myron.

Vous pouvez avoir should_receive exécuter la méthode originale comme ceci:

 @baker.should_receive(:make_batter, &@baker.method(:make_batter)) 

should_receive et stub prennent en charge la transmission d’une implémentation de bloc (évaluée lors de l’appel de la méthode). &@baker.method(:make_batter) récupère un &@baker.method(:make_batter) de l’object de la méthode d’origine et le transmet comme implémentation du bloc.

FWIW, nous aimerions fournir une API plus agréable à déléguer à la méthode d’origine (voir ce problème ), mais il est difficile d’append cette fonctionnalité sans compromettre la compatibilité descendante.

Vous rencontrez ce problème avec should_receive car vous testez les détails d’implémentation de la méthode make_cake . Lorsque vous écrivez des tests, vous devez vous concentrer uniquement sur le comportement et non sur une séquence d’appels de méthodes internes. Sinon, le refactoring de votre code entraînera également une refonte complète de tous vos tests.

Mocks et Stubs sont pratiques lorsque vous souhaitez tester vos cours de manière isolée. Lorsque vous écrivez des tests unitaires, votre sujet de test doit être isolé de tout autre object. Les deux agissent en tant que remplaçants lorsque vous travaillez avec plusieurs objects à la fois. Dans ce cas, vous pouvez utiliser should_receive pour vous assurer que votre sujet de test délègue correctement une tâche à un autre object en appelant une méthode.