Setting partial stub for just one value and letting obj handle the rest

Occasionally, I find myself in a situation where I want to have a mock
obj returned if a method is called with a particular argument but
handled normally otherwise. For example, lets say I have a Model
named User and I am specing a controller that sends messages from one
user to another. When User.find is called for the user who is making
the request I want it to run normally but when User.find is called for
the receiver I want it to return a mocked obj. In this case, I can do
something like (gist:352305 · GitHub):

user = mock_model(User)
User.stub!(:find).at_least(1).and_return do |id|
if id == mock_user.id.to_s
user
else
User.find_by_id(id)
end
end

If I didn’t have another method that allowed me to find a User by it’s
id this won’t work.

Is there an easier way to accomplish this?

On Apr 1, 2010, at 3:14 PM, drewB wrote:

User.stub!(:find).at_least(1).and_return do |id|
Is there an easier way to accomplish this?
Not really. When you stub a method, the framework overrides that method
with its own implementation. There’s no mechanism in place to say “pass
the message onto the real object if it doesn’t have the arguments I’m
interested in.” I’m not sure of any framework that does that. Maybe RR,
but I’m not sure.

Good luck.
David

On 1 Apr 2010, at 21:35, David C. wrote:

the receiver I want it to return a mocked obj. In this case, I can
end
arguments I’m interested in." I’m not sure of any framework that
does that. Maybe RR, but I’m not sure.

Good luck.
David

I can’t help but chime in here that I would be pretty irritated to
come across a test that mixed up using mocks and real objects,
especially when they’re the same class. Can you not use a mock for the
other instance of User too?


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

+447974 430184

David, thanks for your response.

Matt, I totally hear you. In this contrived example, you probably
could but in the project I am working on it would be very difficult.
One of the challenges of joining a project already in progress…

For anyone who might come across this message looking for a solution
to the same problem, I wrote the following function to take care of it
(gist:352449 · GitHub)

def stub_find_for_specific_values(model, stubs)
model.stub!(:find).at_least(1).and_return do |id|
if stubs.has_key? id
stubs[id]
else
model.find_by_id(id)
end
end
end

#example below will return the mock_user if its id is search for
otherwise find will search as normal
mock_user = mock_model(User)
stub_find_for_specific_values(User, mock_user.id => mock_user)

On 1 Apr 2010, at 23:12, drewB wrote:

David, thanks for your response.

Matt, I totally hear you. In this contrived example, you probably
could but in the project I am working on it would be very difficult.
One of the challenges of joining a project already in progress…

I have felt that pain many times :slight_smile:

This book is a great read when you’re working with other people’s crap:
http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

obj returned if a method is called with a particular argument but

it’s
Good luck.



rspec-users mailing list
[email protected]://rubyforge.org/mailman/listinfo/rspec-users


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

+447974 430184

I used to do the following when I used rspec mocks.

user = mock_model(User)
find_method = User.method(:find)
User.stub!(:find).at_least(1).and_return do |id|
if id == mock_user.id.to_s
user
else
find_method.call(id) # May need to instance_eval here, but I
think .call is sufficient.
end
end

In fact this sort of inspired me to mock.proxy method call. Of course
YMMV :slight_smile: