2

私は最近、Ruby 2.0、Rails 4、および Rspec 2.13.1 でこの奇妙な動作を発見しました。

を使用してインスタンス メソッドをスタブするClassName.any_instance.stub(:method_name)と、作成した過去のインスタンスが正しくスタブされます。ただし、戻り値を変更して再タブすると、古いインスタンスは新しいスタブ値ではなく、古いスタブ値を返します。

たとえば、このダミーのクラス定義があります

class A
  def test(x)
    return x
  end
end

そして、このテストは動作を説明しています:

it 'strange stubbing behavior' do
  inst = A.new
  inst.test(1).should eq 1                         #passes
  A.any_instance.stub(:test).and_return(10)
  inst.test(0).should eq 10

  A.any_instance.unstub(:test)                     #has no effect
  A.any_instance.stub(:test).and_return(100)

  inst.test(0).should eq 100                       #expects 100, got 10

  A.any_instance.stub(:test) do |a|
    a + 2
  end
  inst.test(3).should eq 5   #also fails           # also got 10
end

rspec がこのように動作するのはなぜですか? それは定義された動作ですか?もしそうなら、古いインスタンスを再スタブする適切な方法は何ですか? それともバグですか?

編集:他の誰かが「質問に質問する」という答えを出す前に、仕様を再考して再編成することで元の問題を解決したことを指摘したいと思います。しかし、なぜRSpecがこのように振る舞うかについてはまだ興味があります

4

2 に答える 2

2

要するに、既存のインスタンスでスタブが呼び出されany_instance.unstub た場合に使用すると、RSpec は実際に既存のインスタンスのスタブを解除しないようです。同様に、any_instance.stubあなたが発見したように、以前にスタブ化された/呼び出されたインスタンスではスタブ化は機能しません。

ただし、既存のインスタンスを呼び出したり、明示的にスタブ解除したりしない場合、新しいstubを持つすべてのany_instanceはそのインスタンスで期待どおりに機能します。たとえば、例に対する次の変更は機能します。

it 'strange stubbing behavior' do
  inst = A.new
  inst.test(1).should eq 1                         #passes
  A.any_instance.stub(:test).and_return(10)
  # SKIP THE INVOCATION SO TEST WILL PASS
  # inst.test(0).should eq 10

  A.any_instance.unstub(:test)                     #has no effect (on existing instances)

  A.any_instance.stub(:test).and_return(100)

  inst.test(0).should eq 100                       #expects 100, got 10

  inst.unstub(:test) # UNSTUB INSTANCE SO TEST WILL PASS                                                            
  A.any_instance.stub(:test) do |a|
    a + 2
  end
  inst.test(3).should eq 5   #also fails           # also got 10
end

これが予想される動作かどうかはわかりませんが、問題を提出しました。https://www.relishapp.com/rspec/rspec-mocks/docs/method-stubs/stub-on-any-instance-of-a-class#any-instance-unstubで表示可能な RSpec Cucumber テストのみunstub新しいインスタンスで機能するテスト。

(@Theresa Luu の協力に感謝します。)

于 2013-08-07T02:29:09.567 に答える