我试图测试一个简单的索引视图,里面有以下代码:
- 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
和控制器中,但没有任何效果。
答案 0 :(得分:29)
这在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
答案 1 :(得分:5)
zetetic发布的'之前:每个'代码对我不起作用。我对'can?'的看法很开心方法因为视图中的'current_ability'返回nil。我通过使用'before:each'代码来修复它:
@ability = Ability.new(user)
assign(:current_ability, @ability)
controller.stub(:current_user, user)
view.stub(:current_user, user)
以上代码模拟登录。
答案 2 :(得分:4)
在您的spec_helper中:
config.include Devise::TestHelpers, :type => :view
在您的观看规范中:
controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])
答案 3 :(得分: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
答案 4 :(得分:1)
CanCan wiki解决方案的问题在于,每个示例中都需要@ability. can ...
,感觉不会很干。
此外,它实际上并没有隐藏能力本身,而是返回控制器能力的方法。能力不是存根,因此检查能力。
如果您正在使用Rspec并且想要仅测试控制器(而不是它的能力),那么这里是如何将其存根:
before(:each) do
ability = mock(:ability).as_null_object
controller.stub(:current_ability).and_return(ability)
end
这是有效的,因为as_null_object
会返回所有方法的真值,因此能力检查方法会通过。
答案 5 :(得分:0)
基于John Kloian的示例,我定义了这个有用的帮助器:
# spec/support/sign_in.rb
module ViewSpecSignInHelper
def login_as(user)
allow(view).to receive(:signed_in?).and_return true
allow(controller).to receive(:current_user).and_return user
end
end
RSpec.configure do |config|
config.include ViewSpecSignInHelper, type: :view
end
我的完整spec/support/sign_in.rb
看起来像这样:
module ControllerSpecSignInHelper
def login_as(user)
sign_in(user)
end
end
module FeatureSpecSignInHelper
# See https://github.com/plataformatec/devise/wiki/How-To%3a-Test-with-Capybara
include Warden::Test::Helpers
Warden.test_mode!
# A login_as(user) method is provided already!
end
module ViewSpecSignInHelper
def login_as(user)
allow(view).to receive(:signed_in?).and_return true
allow(controller).to receive(:current_user).and_return user
end
end
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include ControllerSpecSignInHelper, type: :controller
config.include FeatureSpecSignInHelper, type: :feature
config.include ViewSpecSignInHelper, type: :view
end
我现在可以在功能,控制器和查看规格中以相同的方式登录用户:
user = create :user # Using FactoryBot
login_as user