Тестирование просмотров, которые используют CanCan и Devise с RSpec
Я пытался проверить простой индексный просмотр, который имеет следующий код внутри:
- if can? :destroy, MyModel
%th Options
MyModelsController
имеет следующие параметры (Inherited Resources + 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
, так и в контроллере, но это не дало эффекта.
Ответы
Ответ 1
Это описано в CanCan docs для тестирования контроллера, а также может быть изменено для применения к спецификациям вида. Вот один из способов сделать это:
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
Ответ 2
Код "до: каждый", отправленный zetetic, не работает для меня. Мои взгляды на "может"? потому что 'current_ability' в представлении возвращает nil. Я исправил его, используя вместо этого код "before: each":
@ability = Ability.new(user)
assign(:current_ability, @ability)
controller.stub(:current_user, user)
view.stub(:current_user, user)
Вышеупомянутый код моделирует логин.
Ответ 3
В вашем spec_helper:
config.include Devise::TestHelpers, :type => :view
В вашем представлении spec:
controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])
Ответ 4
Для нового синтаксиса 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
Ответ 5
Проблема с решением из вики CanCan заключается в том, что в каждом примере требуется @ability. can ...
, который не чувствует себя очень СУХОЙ.
Кроме того, он фактически не заглушает сами способности, а метод, который возвращает способность контроллера. Способность не является заглушкой, и, следовательно, возможности проверяются.
Если вы используете Rspec и хотите протестировать только контроллер (а не его способности), вот как его заглушить:
before(:each) do
ability = mock(:ability).as_null_object
controller.stub(:current_ability).and_return(ability)
end
Это работает, потому что as_null_object
возвращает правдивые значения для всех методов, поэтому методы проверки способности проходят.