Тестирование представлений, использующих 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 и контроллер, но это не дало никаких эффектов.

5 ответов


это описано в документы CanCan для тестирования контроллера, а также может быть изменен, чтобы применить для просмотра спецификаций. Вот один из способов сделать это:

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

код "до :каждый", опубликованный zetetic, не работает для меня. Мои взгляды Борк на может?"метод, потому что "current_ability" в представлении возвращает nil. Я исправил это, используя этот код "before :each" вместо:

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

приведенный выше код имитирует входа.


в spec_helper:

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

на ваш взгляд spec:

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

для нового синтаксиса 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

проблема с решением из Cancan wiki заключается в том, что для этого требуется @ability. can ... в каждом примере, который не чувствует себя очень сухой.

более того, на самом деле это не заглушает сами способности, а метод, который возвращает способность контроллера. Способность не является заглушкой, и, следовательно, способности проверяются.

Если вы используете Rspec и хотите проверить только контроллер( а не его способности), вот как заглушить его out:

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

это работает, потому что as_null_object возвращает истинные значения для всех методов, поэтому методы проверки способности проходят.