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?
To call a module method, you specify the name of the module, and the name of the method, separated by a dot. Like this: MyModule. my_method. But you can also include modules into classes so that those classes inherit all the module's instance methods.
In RSpec, a stub is often called a Method Stub, it's a special type of method that “stands in” for an existing method, or for a method that doesn't even exist yet. Here is the code from the section on RSpec Doubles − class ClassRoom def initialize(students) @students = students End def list_student_names @students.
Use the allow method with the receive matcher on a test double or a real. object to tell the object to return a value (or values) in response to a given. message. Nothing happens if the message is never received.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With