Stubbing a call path

25 views
Skip to first unread message

Dieter Komendera

unread,
Dec 25, 2008, 11:47:44 AM12/25/08
to mocha-developer
Hi there,

I did a little extension for Mocha which I wanted to share. It's about
stubbing a call path.

So before I had to write something like this:

@account.stubs('users').returns(mock('users', :activated => mock
('activated', :find_by_email => users(:kommen))))

With the extension this can now be written as this:

@account.stub_path("users.activated.find_by_email").returns(users
(:kommen))

Story: http://soakedandsoaped.com/articles/read/stubbing-a-call-path-with-mocha
Code: http://gist.github.com/39288

Is there any interest in getting such a feature into mocha? Or is
there maybe a (better) method which already does what I want and I
just missed it?

Happy Holidays!

Cheers,
Dieter

Duncan Beevers

unread,
Dec 25, 2008, 4:22:20 PM12/25/08
to mocha-d...@googlegroups.com
I haven't looked over the implementation, but this reminds me of FlexMock Demeter-Chain Mocks.

 # Demeter chain mocking using the short form.
car = flexmock("car")
car.should_receive( "chassis.axle.universal_joint.cog.turn" => :ok).once

As you point out, traditional single-method mocking can get really unwieldy when using features like Rails' named scopes.  In general, I try to avoid mocking database-dependent operations, but if it's necessary, instead of mocking long named scope chains I create explicit, composite scopes.

class User < ActiveRecord::Base
  named_scope :having_email, lambda { |email| { :conditions => { :email => email } } }
  named_scope :registered, :conditions => { :registered => true }
  def self.registered_having_email email
    registered.having_email(email)
  end
end

Anyway, I haven't time to look over the implementation at the moment, but I favor having the tool available, though clearly it needs to be used judiciously.

Also, if you look over the FlexMock documentation, you'll notice that it creates a series of mocks and expectations, which can lead to weirdo error messages when one named scope in a chain goes away due to refactoring or something.

Dieter Komendera

unread,
Dec 26, 2008, 8:36:20 AM12/26/08
to mocha-developer
I also used to create such explicit, composite scopes. However, I like
the flexibility which is provided by just combining named scopes–
actually I think that's one of their main advantages to not have to
write such methods and add clutter to the model. Also changing the
application code only to make testing easier doesn't sound right to
me, so I looked for possibilities to just make it easier to testing
these cases.

Thanks for the hint to FlexMock, haven't heard of it. Definitely will
have a look at it.

James Mead

unread,
Jan 3, 2009, 8:06:21 AM1/3/09
to mocha-d...@googlegroups.com
2008/12/26 Dieter Komendera <dieter.k...@gmail.com>
Hi Dieter,

Sorry for the slow response. I haven't had much free time over the holiday period.

Like Duncan, I too have reservations about stubbing long chains of named scopes. I would favour writing explicit composite scopes which express the purpose of the scope in as domain-specific language as possible i.e. not necessarily just combining the names of the scopes with the word "and".

One danger of stubbing such long chains of named scopes is that the order of the scopes is not important in terms of the result, but it is important in how the various stubs are set up. This makes the test more brittle and tied to the implementation details of the code e.g. calling account.users.registered.having_email('j...@bloggs.com') gives the same result as calling account.users.having_email('j...@bloggs.com').registered, but only one combination would be covered by an invocation of stub_path e.g. account.stub_path("users.activated.find_by_email") and the code might call the other combination. This problem goes away if you use a composite scope.

In general mocking and stubbing doesn't tend to work as well when you move away from a classic OO style towards a more DSL-like style, as Rails has done in this and other cases.

I disagree with you that changing application code to make testing easier is *necessarily* a bad thing. Often the fact that testing some application code is hard is an indicator of a code smell [1].

Having said all that, although I've always been wary about introducing features into Mocha that might encourage people to get themselves in a mess, this seems like an example where it might be sensible to be pragmatic. Another example of this is Brian Takita's method interception functionality [2].

I've also tried not to introduce anything Rails-specific into Mocha, to ensure that it's useful to Ruby developers outside Rails and to avoid a maintenance nightmare. However, a few recent requests seem very reasonable e.g. the introduction of mock_model [3].

I'm starting to think the best way to provide for these requests is to have one or more optionally required bits of Mocha (much as Ken Collins suggested in [2]).

What do people think?

Cheers, James.
http://blog.floehopper.org

[1] http://www.mockobjects.com/2007/03/synaesthesia-listening-to-test-smells.html
[2] http://groups.google.com/group/mocha-developer/browse_thread/thread/4982d02b819dec7c
[3] http://groups.google.com/group/mocha-developer/browse_thread/thread/a73e35684af9611f

floehopper

unread,
Jan 3, 2009, 8:14:37 AM1/3/09
to mocha-developer
I've added a Lighthouse ticket for this feature request [1].

Cheers, James.

[1] http://floehopper.lighthouseapp.com/projects/22289-mocha/tickets/23
Reply all
Reply to author
Forward
0 new messages