Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
321 views
in Technique[技术] by (71.8m points)

ruby - Is there a way to stub a method of an included module with Rspec?

I have a module that is included in another module, and they both implement the same method. I would like to stub the method of the included module, something like this:

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

The first test is passing, but the second one outputs:

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

   expected: :bar
        got: :M

Why isn't the stub working in this case? Is there a different way to achieve this?

Thanks!

-------------------------------------UPDATE----------------------------------

Thanks! using allow_any_instance_of(M) solved this one. My next question is - what happens if I use prepend and not include? see the following code:

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 

This time, using allow_any_instance_of(M) results in an infinite loop. why is that?

question from:https://stackoverflow.com/questions/24408717/is-there-a-way-to-stub-a-method-of-an-included-module-with-rspec

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Note you cannot directly call M.foo! Your code only seems to work because you mocked M.foo to return :bar.

When you open A metaclass (class << self) to include M, you have to mock any instance of M, that is adding to your before block:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...