开发者

Sample specs for cancan

I've created a sets of specs for a controller that I have (Photo) that is a nested resource of a User. The specs all pass but some of them fail when I introduce CanCan in the Photos contoller:

load_and_authorize_resource :user
load_and_authorize_resource :photo

Here's a failing test case from one of my specs:

describe "get 'show'" do
   let(:photo) { Factory.stub(:photo) }
   it "searches for the users photo" do 
      @user.photos.should_receive(:find).with(:photo.object_id); 
      get :show, :user_id => @user.id, :id => :photo.object_id; 
   end
   context "when the photo doesn't exist" do
      before do 
         @user.photos.stub(:find).with(:photo.object_id).and_raise(ActiveRecord::RecordNotFound); 
         get :show, :user_id =>开发者_开发技巧; @user.id, :id => :photo.object_id;  
      end
      it "assigns photo to nil" do 
         assigns[:photo].should be_nil;  
      end
      it "renders the '404' template" do 
         response.status.should eql 404; 
         response.should render_template("#{Rails.root.to_s}/public/404.html") end
      end
   end
   ...
 end

I've set up the user at the top of the spec file:

login(:user)

before do
   @user = controller.current_user # this could be any user.
   User.stub!(:find).and_return(@user)
end

and the show method in the Photos controller looks like this:

def show
  # @user = User.find(params[:user_id])
  # @photo = @user.photos.find(params[:id])
end

Note that the action is blank because Cancan performs the finds required automatically. Before I introduced Cancan the two lines in the action weren't commented out.

In my test, when I test that the find method is called on a users photos for example, the test fails. Cancan must be using some other technique to find the users photos (other than @users.photos.find()). Would anyone know how to rewrite the above tests for a controller that users Cancan, i.e. to replace the find stubs with something that will work?

What I'm looking for ideally is some sample specs for a RESTful controller that uses Cancan. Even a spec for the show action would be useful.

Thanks for reading!

Eddie

ps - I'm using Rails 3.0.6, Cancan 1.6.4 and Devise 1.3.3


There's a technical term for this, but there's a style difference in testing where you can either write a test which defines the implementation, our a test that defines the result.

Code like this:

@user.photos.should_receive(:find).with(:photo.object_id); 

Declares that the way that the photo should be fetched is using a find operation on the photos association. As this is not the way that cancan loads the photo object, this is causing you problems in your tests.

An alternative approach is to define the desired outcome and leave the implementation undefined in the test. This makes the tests less brittle, and opens up more opportunities for code refactoring.

assigns[:photo].should eq photo;

A downside of this approach is it requires the use of Factories (Factory.create) instead of Fixtures (Factory.stub), but in my opinion the more flexible testing style justifies it.


there is this answer: Rspec, CanCan and Devise, but i am not really sure I want to patch CanCan. I would much rather understand and spec out the mock in the right way. I know the key issue is that CanCan does not call Contact.new(params[:contact]). Instead it calls contact.attributes = params[:contact] later after it has applied some initial attributes based on the current ability permissions. How to work around that? That is what I'm working now.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜