views:

60

answers:

2

I am pretty new to using rspec and am trying to write my tests for my controllers. I have this controller (I am using mocha for stubbing):

class CardsController < ApplicationController
  before_filter :require_user

  def show
    @cardset = current_user.cardsets.find_by_id(params[:cardset_id])

    if @cardset.nil?
      flash[:notice] = "That card doesn't exist. Try again."
      redirect_to(cardsets_path)
    else
      @card = @cardset.cards.find_by_id(params[:id])
    end
  end
end

I am trying to test this action with something like this:

describe CardsController, "for a logged in user" do
  before(:each) do
    @cardset = Factory(:cardset)
    profile = @cardset.profile
    controller.stub!(:current_user).and_return(profile)
  end

  context "and created card" do
    before(:each) do
      @card = Factory(:card)
    end

    context "with get to show" do
      before(:each) do
        get :show, :cardset_id => @cardset.id, :id => @card.id
      end

      context "with valid cardset" do
        before(:each) do
          Cardset.any_instance.stubs(:find).returns(@cardset)
        end

        it "should assign card" do
          assigns[:card].should_not be_nil
        end

        it "should assign cardset" do
          assigns[:cardset].should_not be_nil
        end

      end
    end
  end
end

The "should assign cardset" test passes, but I cannot figure out how to properly stub this line @card = @cardset.cards.find_by_id(params[:id]) for the "should assign card" test. What is the best way of testing this action, or if I'm on the right track how would I properly stub my Model calls?

A: 

Ok, deleted a previous answer which was wrong.

First: you are stubbing find not find_by_id. Although you don't need to use find_by_id since that is the default for find. So use find

Second: the before :each ordering is going to call the get :show before the you stub Cardset

Third: check your test.log and make sure you are not getting redirected. Your require_user action might cause a redirect before current_user is even set.

class CardsController < ApplicationController
  ...
     @card = @cardset.cards.find(params[:id])
  ...
end

describe CardsController, "for a logged in user" do
  before(:each) do
    @cardset = Factory(:cardset)
    profile = @cardset.profile
    controller.stub!(:current_user).and_return(profile)
  end

  context "and created card" do
    before(:each) do
      @card = Factory(:card)
    end

    context "with get to show" do

      context "with valid cardset" do
        before(:each) do
          Cardset.any_instance.stubs(:find).returns(@cardset)
          get :show, :cardset_id => @cardset.id, :id => @card.id
        end

        it "should assign card" do
          assigns[:card].should_not be_nil
        end

        it "should assign cardset" do
          assigns[:cardset].should_not be_nil
        end

      end
    end
  end
end
The Who
Ok thanks, I will check these things. My reasoning for using find_by_id is that when a record is not found it returns nil instead of throwing an exception, which seemed easier to handle in this situation.
trobrock
I updated my code to what is shown here: http://gist.github.com/461667 I am still getting a failing "should assign card" test, you were correct though I was getting redirected by the `before_filter`
trobrock
A: 

The stubs that I ended up looking for where these

Cardset.stubs(:find_by_id).returns(@cardset)
@cardset.cards.stubs(:find_by_id).returns(@card)
trobrock