rspec: How to stub an instance method called by constructor?

30,732

Solution 1

Here's the commit which adds the feature to rspec - This was on May 25 2008. With this you can do

A.any_instance.stub(do_something: 23)

However, the latest gem version of rspec (1.1.11, October 2008) doesn't have this patch in it.

This ticket states that they yanked it out for maintenance reasons, and an alternative solution hasn't yet been provided.

Doesn't look like you can do it at this point. You'll have to hack the class manually using alias_method or somesuch.

Solution 2

I've found this solution on http://pivotallabs.com/introducing-rr/

new_method = A.method(:new)

A.stub!(:new).and_return do |*args|
  a = new_method.call(*args)
  a.should_receive(:do_something).and_return(23)
  a
end

Solution 3

I don't know how to do that in spec's mock framework, but you can easily swap it out for mocha to do the following:

# should probably be in spec/spec_helper.rb
Spec::Runner.configure do |config|
  config.mock_with :mocha
end

describe A, " when initialized" do
  it "should set x to 42" do
    A.new.x.should == 42
  end
end

describe A, " when do_something is mocked" do
  it "should set x to 23" do
    A.any_instance.expects(:do_something).returns(23)
    A.new.x.should == 23
  end
end

Solution 4

or with RR:

stub.any_instance_of(A).do_something { 23 }

Solution 5

In the latest version of RSpec as of today - 3.5 you can:

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
Share:
30,732
Pedro
Author by

Pedro

Updated on July 14, 2020

Comments

  • Pedro
    Pedro almost 4 years
    class A
      def initialize
        @x = do_something
      end
    
      def do_something
        42
      end
    end
    

    How can I stub do_something in rspec, before the original implementation is called (thus assigning 42 to @x)? And without changing the implementation, of course.