对于Rspec的“should_receive”,是否有一个较less侵入的select?

在编写Rspectesting时,我经常为should_receive感到沮丧。 我想知道是否有一个不太干扰的select。

例如:

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

should_receive的调用是一个很好的描述,但是它破坏了我的代码,因为should_receive通过掩盖原始方法来工作, make_cake不能继续,除非make_batter实际返回一些连击。 所以我改变它:

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

这是丑陋的,因为:

  • 看起来像我testingmake_batter正确地返回@batter ,但我实际上是迫使伪造的版本make_batter返回。
  • 它迫使我分别设置@batter
  • 如果make_batter有任何重要的副作用(这可能是一种代码味道,我想),我也必须做到这一点。

我希望should_receive(:make_batter)将validation方法调用并将其传递给原始方法 。 如果我想将它的行为存储为更好的隔离性testing,我会明确地这样做: @baker.stub(:make_batter).and_return(@batter)

有没有办法做一些像should_receive而不阻止原始方法调用? 我的问题是不良devise的症状吗?

它看起来像更好的API委托给原来的方法,Myron马斯顿暗示实际上已经添加在rspec-mocks v2.12.0

  • 添加and_call_original代表原来的方法。

所以,现在只要你“想要设置一个消息预览而不会干扰对象如何响应消息”,你就可以简单地做到这一点:

 @baker.should_receive(:make_batter).and_call_original 

谢谢你,Myron。

你可以让should_receive像这样运行原始的方法:

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

这两个should_receivestub支持通过一个块实现(当方法被调用时被eval'd)。 &@baker.method(:make_batter)获取原始方法对象的句柄,并将其作为块实现传递。

FWIW,我们想提供一个更好的API委托给原来的方法(见这个问题 ),但是很难在不破坏向后兼容性的情况下添加这个function。

你有这个问题,因为你正在testingmake_cake方法的实现细节。 在编写testing时,应该只关注行为,而不是内部方法调用的序列。 否则,以后重构你的代码会导致所有testing的巨大重构。

当你想单独testing你的课程时,Mock和Stubs派上用场。 在编写unit testing时,应将testing对象与其他对象隔离。 当你一次处理多个对象时,两者都起到了替身的作用。 在这种情况下,您可以使用should_receive来确保您的testing主题通过调用方法正确地将某个任务委托给另一个对象。