[Rspec-devel] define_instance_method, stub_with, and mock_with

David Chelimsky dchelimsky at gmail.com
Sun Aug 27 15:51:00 EDT 2006

On 8/27/06, Brian Takita <brian.takita at gmail.com> wrote:
> Hello,
> At work we came up with a trio of methods that mock out methods in an
> object.
> define_instance_method
> stub_with
> mock_withFunny thing is around the same time, this was posted.
> http://blog.seagul.co.uk/articles/2006/06/30/very-very-lightweight-mocking-ish
> Here is a snippit from that article.
> class Object
>   def metaclass
>     class << self; self; end
>    end
>   def define_instance_method(sym, &block)
>      metaclass.__send__(:define_method, sym, &block)
>   end
>   def stub_instance_method(sym, &block)
>      raise "#{self} does not respond to <#{sym}> and therefore cannot be
> stubbed" unless self.respond_to?(sym)
>      define_instance_method(sym, &block)
>   end
>   def __log__
>     @__log__ ||= []
>   end
>  end
> So you can use this like:
> o = Object.new
>  o.define_instance_method(:foo) do
>   :bar
>  end
> o.foo # return :bar
> We went a little further by adding the mock_with and stub_with methods,
> which take a Hash and allow you to mock out the method names corresponding
> to the keys.
> For example,
> o = Object.new
> two_value = 2
>  o.stub_with(:one => 1, :two => proc {two_value})
> o.one # returns 1
> o.two # returns 2
>  o = Object.new
> mock_action = mock("mock_action")
>  mock_action.should_receive(:something).with(:grey_poupon)
> o.mock_with (:receive => proc {mock_action)}
> o.receive.something(:grey_poupon)
> David, I also remember you where working on acts_as_mock. This has helped us
> with our tests and I think it would also make using specs more convenient
> and easier to read.
> What does everybody think? If it sounds good, I'll create a patch.

I started working on acts_as_mock because rails forces us to use
static methods to find objects, which couples us to the database in
our controller specs:


In retrospect, all we really need is the ability to mock class level
methods and then return a mock:

specify "should display person when show is requested" do
  person = mock("person")
  get 'show'

specify "should ask Person for a new one when create is requested" do
  person = mock("person")
  get 'create'

The code for this much is already in a branch, so I'll revisit that in
the next few days.

As for the idea you are presenting, in general, I think that mocking
methods on real instances is  a risky proposition. I've seen this
result in tests that are very difficult to understand when they fail,
as some methods on the instance are mocked and some are not. I also
have yet to see a case where   using partial mocks is a better
decision than improving the decoupling in the system under test.

That's just my 2 cents. Anyone else?


More information about the Rspec-devel mailing list