views:

915

answers:

3

I want to call a named_scope that will only return one record, but the named_scope returns an array, that's not a big deal as I can just chain it with .first:

Model.named_scope(param).first

and this works, what I am struggling with is how to stub the chained call. Does anyone have a reference or an answer on how I would go about achieving this with Rspec mocking?

+2  A: 

I figured something out.

Client.stub!(:named_scope).and_return(@clients = mock([Client]))
@clients.stub!(:first).and_return(@client = mock(Client))

which allows me to call my controller:

@client = Client.named_scope(param).first

It works, but is there a better solution?

EDIT:

The release of rspec 1.2.6 allows us to use stub_chain meaning it can now be:

Client.stub_chain(:named_scope, :chained_call).and_return(@clients = [mock(Client)])

This was top of my head, as always check the api for specifics :)

railsninja
+1  A: 

I suppose this is in a controller spec?

Your own suggestion should work fine. Another possibility is to move the named_scope call inside your model, to avoid the issue entirely. This would also be in line with the "fat models, thin controllers" advice.

Antti Tarvainen
A: 

I think you've already done the thin controller thing by putting the query into a named scope where it can be reused. Here is some code I used before I started using named scopes.

  def mock_comm(stubs={})
    @mock_comm ||= mock_model(Comm, stubs)
  end

  describe "responding to GET index" do

    it "should expose all comms as @comms" do
      Comm.should_receive(:find).with(:all).and_return([mock_comm])
      get :index
      assigns[:comms].should == [mock_comm]
    end
# ...

I would probably write code quite similar to what you have already, but maybe put it in a helper that allows me to reuse it. The other thing is to use a different mocking framework that maybe gives you more control. Have a look at Ryan Bates' railscast on RSpec - it's a bit old now but still some good ideas in there.

Ghoti