#275 √ invalid
Mislav

mock_model is unusable when using Mocha

Reported by Mislav | February 6th, 2008 @ 02:21 AM

I have configured my specs to use Mocha because, from what I've seen, Mocha is superior to mocking support in RSpec.

Spec::Runner.configure do |config|
  config.mock_with :mocha
end

Unfortunately, mock_model from Spec::Rails is then rendered unusable. That method uses the mock method to set stubs with second argument:

m = mock("#{model_class.name}_#{id}", options_and_stubs)

But, in Mocha, the second argument for mock method are *expected methods*, not stubs! As the result, each call to mock_method sets 4 expectations:

id, to_param, new_record?, errors

Instead, mock_model should use "stub" with Mocha. I have no idea how to accomplish this without branching code internally in the mock_model method. That would possibly turn out simple, but would definitely be ugly. Maybe the mocking frameworks' adapters could be modified instead?

Comments and changes to this ticket

  • David Chelimsky

    David Chelimsky February 6th, 2008 @ 04:09 PM

    • → Assigned user changed from “” to “David Chelimsky”
    • → State changed from “new” to “invalid”

    Sorry, but I think if you're using a mock framework other than RSpec's, it is up to that framework to satisfy this problem. Flexmock, for example already has a mock_model (or similar) method.

    I'd raise this issue in the mocha tracker.

  • Mislav

    Mislav February 6th, 2008 @ 04:33 PM

    I don't see why I should file this in the Mocha tracker. It certainly is not a bug in their framework. I've filed the issue here because this is a case of APIs that don't match: mock in RSpec isn't equivalent to mock in Mocha.

    Isn't that the issue of the adapters in RSpec? The adapters were there to hide the frameworks' APIs under one common API.

  • David Chelimsky

    David Chelimsky February 6th, 2008 @ 04:20 PM

    The adapters are there to support using other frameworks, not to hide them from you. Nor are they there to enhance other frameworks.

    If the adapter was hiding mocha from you then it would force you to say "should_receive" instead of "expects" and delegate that call to mocha.

    Plus, making this a mocha feature request will benefit all users of mocha, not just those who choose rspec.

  • Mislav

    Mislav February 6th, 2008 @ 04:26 PM

    I see. You are right. But if I suggest/contribute the mock_model feature to Mocha and it gets added under that name, isn't the method from Spec::Rails still going to be called when I use mock_model in my specs?

  • David Chelimsky

    David Chelimsky February 6th, 2008 @ 04:40 PM

    Now that's a horse of a different color!

    There are a couple of other convenience methods that rely on rspec's

    mocks that init Spec::Mocks::Mock explicitly instead of using the mock

    method. In this case, we need to actually redefine the method.

    That could probably be handled in the mocha adapter by having it undef

    mock_model before mixing in the mocha methods. WDYT?

  • Mislav

    Mislav February 6th, 2008 @ 05:08 PM

    I'm definitely for undef, which can even be done unconditionally (regardless of the Mocha version I mean) because mock_model is unusable, anyway.

  • Jeremy Friesen

    Jeremy Friesen June 5th, 2008 @ 08:34 PM

    I applied the following dirty hack to my spec_helper.rb

    1. Brings in the __mock_proxy

    Mocha::Mock.send(:include, Spec::Mocks::Methods)

    1. Overwrites :mock method with :stub, so I stop
    2. getting exceptions for to_params not being called

    Test::Unit::TestCase.send(:alias_method, :mock, :stub)

  • Mislav

    Mislav June 6th, 2008 @ 02:26 PM

    Your hacks are indeed dirty, especially the other one which, uh, overwrites the "mock" method everywhere.

    These are my hacks which are not destructive:

    # override spec-rails stuff because of Mocha
    module Spec::Rails::Mocks
      def mock_model(model_class, options_and_stubs = {})
        id = next_id
        options_and_stubs.reverse_merge! :id => id,
          :to_param => id.to_s,
          :new_record? => false,
          :errors => stub("errors", :count => 0)
          
        m = stub("#{model_class.name}_#{options_and_stubs[:id]}", options_and_stubs)
        m.instance_eval <<-CODE
          def is_a?(other)
            #{model_class}.ancestors.include?(other)
          end
          def kind_of?(other)
            #{model_class}.ancestors.include?(other)
          end
          def instance_of?(other)
            other == #{model_class}
          end
          def class
            #{model_class}
          end
        CODE
        yield m if block_given?
        m
      end
      
      # fixes spec_model
      def add_stubs(object, stubs = {})
        m = String === object || Symbol === object ? mock(object.to_s) : object
        stubs.each { |k, v| m.stubs(k).returns(v) }
        m
      end
    end
    
  • David Chelimsky

    David Chelimsky June 6th, 2008 @ 03:28 PM

    Mislav - I'm thinking that RSpec's mock_model should be disabled if other frameworks are being used - then you could release your code as a plugin for all the world to use w/o monkey patching.

    WDYT?

  • Mislav

    Mislav June 6th, 2008 @ 08:25 PM

    I agree that mock_model and stub_model should be disabled. But I also think that Mocha equivalents of these could be included with RSpec. I could contribute that.

  • David Chelimsky

    David Chelimsky June 6th, 2008 @ 08:34 PM

    I'd rather you publish them separately. We've had a couple of similar contributions in the past that stopped working when the other libraries changed, increasing what is already a significant maintenance burden.

    Are you open to publishing/maintaining your own plugin?

  • Mislav

    Mislav June 6th, 2008 @ 08:47 PM

    Yeah, I will use it myself so no problem pushing it on GitHub. I would probably call it "rspec-mocha" (following the "rspec-rails" convention).

  • gravelpup

    gravelpup August 28th, 2008 @ 11:40 PM

    • → Tag changed from “” to “mocha mocks mock_model rspec_on_rails stubs”

    @Mislav: any progress on that plugin? I'd be interested in grabbing it when it's up on GitHub.

  • Mislav

    Mislav August 29th, 2008 @ 03:50 AM

    • → Tag cleared.

    Sorry I forgot about this; now it's imported http://github.com/mislav/rspec-r...

  • gravelpup

Please Login or create a free account to add a new comment.

You can update this ticket by sending an email to from your email client. (help)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Behaviour Driven Development for Ruby.

Shared Ticket Bins