2011-02-16 44 views
19

我試圖測試一個簡單的索引視圖,裏面有以下代碼:測試使用CanCan和Devise與RSpec的視圖

- if can? :destroy, MyModel 
    %th Options 

MyModelsController有以下選項(繼承資源+ CanCan + Devise):

class MyModelsController < ApplicationController 
    inherit_resources 
    nested_belongs_to :mymodel 
    before_filter :authenticate_user! 
    load_and_authorize_resource :project 
    load_and_authorize_resource :mymodel, :through => :project 

運行規格時崩潰在線- if can? :destroy, MyModel

Failure/Error: render 
    ActionView::Template::Error: 
     undefined method `authenticate' for nil:NilClass 

沒有回溯,沒有什麼可以基於...

我認爲可能在測試視圖時我沒有被授權和簽名,但Devise::TestHelpers應該只包含在控制器測試中(這就是我的方式)。

我試圖覆蓋方法可以嗎?在Ability和控制器中,但沒有任何效果。

回答

28

這在CanCan docs for controller testing中有描述,也可以修改爲適用於查看規格。以下是一種方法:

require 'spec_helper' 

describe "mymodel/index.html.erb" do 
    before(:each) do 
    assign(:my_model,mock_model(MyModel)) 
    @ability = Object.new 
    @ability.extend(CanCan::Ability) 
    controller.stub(:current_ability) { @ability } 
    end 

    context "authorized user" do 
    it "can see the table header" do 
     @ability.can :destroy, MyModel 
     render 
     rendered.should have_selector('th:contains("Options")') 
    end 
    end 

    context "unauthorized user" do 
    it "cannot see the table header" do 
     render 
     rendered.should_not have_selector('th:contains("Options")') 
    end 
    end 
end 
+0

我不知道我怎麼錯過了它,但它完美,謝謝! – farnoy

+0

我也必須存'view.current_ability'以及'controller',但這是完美的 – Gareth

+0

賓果!!!!!!!!!! –

5

zetetic發佈的'before:each'代碼不適用於我。我對「可以嗎?」的看法方法,因爲視圖中的'current_ability'返回nil。我通過使用'之前的'每個'代碼來修復它:

@ability = Ability.new(user) 
assign(:current_ability, @ability) 
controller.stub(:current_user, user) 
view.stub(:current_user, user) 

上面的代碼模擬登錄。

4

在你spec_helper:

config.include Devise::TestHelpers, :type => :view 

在你看來規格:

controller.stub!(current_user: [some user]) 
view.stub!(current_user: [some user]) 
+0

工作噸工作!我試圖包括Devise :: TestHelpers,:type =>:controller之前,但仍有一個問題。包括助手查看固定) – ajahongir

1

從慘慘維基解決方案的問題是,它需要在每個例如@ability. can ...,這不感覺非常乾燥。而且,它本身並沒有真正地剔除能力,而是返回控制器能力的方法。能力不是存根,因此能力被檢查。

如果你正在使用Rspec的和想測試只是控制器(而不是它的能力),這裏是如何存根出來:

before(:each) do 
    ability = mock(:ability).as_null_object 
    controller.stub(:current_ability).and_return(ability) 
end 

這工作,因爲所有的方法as_null_object回報truthy值,因此能力檢查方法通過。

2

對於新RSpec的3.0語法

before(:each) do 
    assign(:my_model,mock_model(MyModel)) 
    @ability = Object.new.extend(CanCan::Ability) 
    allow(controller).to receive(:current_ability).and_return(@ability) 
    end