cancan的样品规格

时间:2011-04-27 11:43:18

标签: rspec devise cancan

我为控制器创建了一组规格(Photo),它是用户的嵌套资源。 规范全部通过但是当我在照片控制器中引入CanCan时,其中一些失败了:

load_and_authorize_resource :user
load_and_authorize_resource :photo

以下是我的一个规范中的失败测试用例:

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

我已将用户设置在spec文件的顶部:

login(:user)

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

并且Photos控制器中的show方法如下所示:

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

请注意,该操作为空,因为Cancan会自动执行所需的查找。在我介绍Cancan之前,行动中的两行没有被注释掉。

在我的测试中,例如,当我测试在用户照片上调用find方法时,测试失败。 Cancan必须使用其他技术来查找用户照片(@ users.photos.find()除外)。有谁知道如何为用户Cancan的控制器重写上述测试,即用可以工作的东西替换查找存根?

我正在寻找的理想情况是使用Cancan的RESTful控制器的一些示例规范。即使是节目动作的规范也很有用。

感谢阅读!
埃迪

ps - 我正在使用Rails 3.0.6,Cancan 1.6.4和Devise 1.3.3

2 个答案:

答案 0 :(得分:2)

这有一个技术术语,但测试中存在风格差异,您可以编写定义实现的测试,定义结果的测试。

这样的代码:

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

声明应该获取照片的方式是在照片关联上使用查找操作。由于这不是cancan加载照片对象的方式,这会导致测试中出现问题。

另一种方法是定义所需的结果,并在测试中保持实现未定义。这使得测试不那么脆弱,并为代码重构提供了更多机会。

assigns[:photo].should eq photo;

这种方法的缺点是它需要使用工厂(Factory.create)而不是Fixtures(Factory.stub),但在我看来,更灵活的测试风格证明了它的合理性。

答案 1 :(得分:0)

答案是:Rspec, CanCan and Devise,但我不确定是否要修补CanCan。我更愿意理解并以正确的方式指出模拟。我知道关键问题是CanCan不会调用Contact.new(params [:contact])。相反,它在根据当前能力权限应用了一些初始属性后,稍后调用contact.attributes = params [:contact]。如何解决这个问题?这就是我现在正在做的事情。