web-dev-qa-db-ja.com

含まれるモジュールのメソッドをRspecでスタブ化する方法はありますか?

別のモジュールに含まれるモジュールがあり、両方とも同じメソッドを実装しています。含まれているモジュールのメソッドを次のようにスタブしたいと思います。

module M
  def foo
    :M
  end
end

module A
  class << self
    include M

    def foo
      super
    end
  end
end

describe "trying to stub the included method" do
  before { allow(M).to receive(:foo).and_return(:bar) }

  it "should be stubbed when calling M" do
    expect(M.foo).to eq :bar
  end

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end

最初のテストはパスしていますが、2番目のテストは出力します:

Failure/Error: expect(A.foo).to eq :bar

   expected: :bar
        got: :M

この場合、スタブが機能しないのはなぜですか?これを達成する別の方法はありますか?

ありがとう!

- - - - - - - - - - - - - - - - - - -更新 - - - - - - ----------------------

ありがとう! allow_any_instance_of(M)を使用してこれを解決しました。次の質問は-prependを使用し、includeを使用しない場合はどうなりますか?次のコードを参照してください。

module M
  def foo
    super
  end
end

module A
  class << self
    prepend M

    def foo
      :A
    end
  end
end

describe "trying to stub the included method" do
  before { allow_any_instance_of(M).to receive(:foo).and_return(:bar) }

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end 

今回、allow_any_instance_of(M)を使用すると、無限ループが発生します。何故ですか?

27
user3775153

_M.foo_を直接呼び出すことはできません。 _M.foo_を返すために_:bar_をモックしたため、コードは機能しているように見えます。

Aメタクラス(_class << self_)を開いてMを含める場合、Mのインスタンスをモックする必要があります。これは、beforeブロックに追加しています。

allow_any_instance_of(M).to receive(:foo).and_return(:bar)

_module M
  def foo
    :M
  end
end

module A
  class << self
    include M

    def foo
      super
    end
  end
end

describe "trying to stub the included method" do
  before do
    allow(M).to receive(:foo).and_return(:bar)
    allow_any_instance_of(M).to receive(:foo).and_return(:bar)
  end


  it "should be stubbed when calling M" do
    expect(M.foo).to eq :bar
  end

  it "should be stubbed when calling A" do
    expect(A.foo).to eq :bar
  end
end
_
32
mdemolin