Is there a way to stub a method of an included module with Rspec?
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
Admin
Updated on July 25, 2022Comments
-
Admin almost 2 years
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?
-
Peter Ehrlich over 8 yearsThis works. Apparently, unlike
allow
,allow_any_instance_of
doesn't require the method to be defined on the object. -
Derek about 8 yearsi think this just helped me solve 5+ hours worth of banging my head on the table. thanks!
-
Daniel Bidulock almost 8 yearsCf.,
expect_any_instance_of
... this put me on the right track