Issue stubbing with RSpec
rspec, ruby, stub
Solution
The "spy pattern" of RSpec requires that the objects have been previously stubbed. However, `any_instance.stub` doesn't actually stub the methods "for real" unless/until the method is invoked on a particular object. As such, the methods appears as being "unstubbed" and you get the error you're getting. Here's some code that demonstrates the change in definition:
class Foo
end
describe "" do
it "" do
Foo.any_instance.stub(:bar)
foo1 = Foo.new
foo2 = Foo.new
print_bars = -> (context) {puts "#{context}, foo1#bar is #{foo1.method(:bar)}, foo2#bar is #{foo2.method(:bar)}"}
print_bars['before call']
foo1.bar
print_bars['after call']
end
end
which produces the following output:
before call, foo1#bar is #<Method: Foo#bar>, foo2#bar is #<Method: Foo#bar>
after call, foo1#bar is #<Method: #<Foo:0x007fc0c3842ef8>.bar>, foo2#bar is #<Method: Foo#bar>
I reported this an issue on RSpec's github site and got this acknowledgement/response.
You can use the following alternative approach, which depends on the recently introduced `expect_any_instance_of` method.
class Roll
def initialize
install if !installed?
end
def install; puts 'install'; end
end
describe Roll do
before do
class RollTestClass < Roll; end
end
let(:roll_class) { RollTestClass }
let(:roll) { RollTestClass.new }
context 'when installed is true' do
before do
roll_class.any_instance.stub(:installed?).and_return(true)
end
it 'should not call install' do
expect_any_instance_of(roll_class).to_not receive(:install)
roll
end
end
context 'when installed is false' do
before do
roll_class.any_instance.stub(:installed?).and_return(false)
end
it 'should call install' do
expect_any_instance_of(roll_class).to receive(:install)
roll
end
end
end
Problem
I am trying to understand why the result of these tests, the first test claims the method is not stubbed, however, the 2nd one is. ``` class Roll def initialize install if !installed? end def install; puts 'install'; end end describe Roll do before do class RollTestClass < Roll; end RollTestClass.any_instance.stub(:install) end let(:roll_class) { RollTestClass } let(:roll) { RollTestClass.new } context 'when installed is true' do before do roll_class.any_instance.stub(:installed?).and_return(true) end it 'should not call install' do expect(roll).to_not have_received(:install) end end context 'when installed is false' do before do roll_class.any_instance.stub(:installed?).and_return(false) end it 'should call install' do expect(roll).to have_received(:install) end end end ``` It's also strange the error says `expected to have received install`, but I think that is likely just faulty feedback from the RSpec DSL. But maybe worth noting. ``` 1) Roll when installed is true should not call install Failure/Error: expect(roll).to_not have_received(:install) #<RollTestClass:0x10f69ef78> expected to have received install, but that method has not been stubbed. ```