Reputation: 2258
I've coded the following spec:
it "should call user.invite_friend" do user = mock_model(User, :id => 1) other_user = mock_model(User, :id => 2) User.stub!(:find).with(user.id).and_return(user) User.stub!(:find).with(other_user.id).and_return(other_user) user.should_receive(:invite_friend).with(other_user) post :invite, { :id => other_user.id }, {:user_id => user.id} end
But I'm getting the following error when I run the specs
NoMethodError in 'UsersController POST invite should call user.invite_friend' undefined method `find' for # Class:0x86d6918 app/controllers/users_controller.rb:144:in `invite' ./spec/controllers/users_controller_spec.rb:13:
What's the mistake? Without .with it works just fine, but I want different return values for different arguments to the stub method. The following controller's actions might be relevant:
def invite me.invite_friend(User.find params[:id]) respond_to do |format| format.html { redirect_to user_path(params[:id]) } end end def me User.find(session[:user_id]) end
Upvotes: 0
Views: 637
Reputation: 47548
The error arises because the stub gets "used up" by the first call to find
. The second find
is not stubbed, so you get the NoMethodError.
Someone can correct me if I'm wrong, but .with
appears to have an odd effect on stubs when you call it more than once. Rspec seems to associate each message of the same argument type with a single stub. But another argument type effectively creates a different stub. So in your case, you can fix it by calling the second find
with a string:
User.stub!(:find).with(other_user.id.to_s).and_return(other_user)
which is lucky for you, because in fact the controller is expecting a string in the params
hash.
This doesn't answer the larger question of: how do I stub multiple method calls with parameters of the same argument type? In my experience, you can't do that.
Of course you can get around it by not specifying the arguments at all. In your case, I'd say that testing find
itself is not pertinent to your controller -- in effect, you're testing whether ActiveRecord can do a database lookup on a primary key, which is already well tested. So if all you need is to stub the responses to find
in the right order, you can do this:
User.stub!(:find).and_return(user,other_user)
Upvotes: 1