21

我试图测试一个简单的索引视图,其中包含以下代码:

- if can? :destroy, MyModel
  %th Options

MyModelsController有以下选项(继承资源 + CanCan + 设计):

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

4

6 回答 6

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
于 2011-02-16T21:35:12.377 回答
6

zetetic 发布的“之前:每个”代码对我不起作用。我对“罐头”的看法不合时宜。方法,因为视图中的 'current_ability' 返回 nil。我通过使用这个“之前:每个”代码来修复它:

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

上面的代码模拟了一次登录。

于 2012-01-14T12:38:36.627 回答
5

在您的 spec_helper 中:

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

在您的视图规范中:

controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])
于 2013-05-03T15:44:16.180 回答
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
于 2014-01-04T10:14:46.733 回答
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所有方法都返回了真值,因此能力检查方法通过了。

于 2013-06-09T11:02:15.737 回答
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
于 2019-09-11T08:33:21.867 回答