测试使用CanCan和Devise与RSpec的视图

时间:2011-02-16 15:28:20

标签: ruby-on-rails ruby rspec devise cancan

我试图测试一个简单的索引视图,里面有以下代码:

- 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和控制器中,但没有任何效果。

6 个答案:

答案 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