RSpec: тестирование cancan с проверкой подлинности - PullRequest
0 голосов
/ 10 августа 2011

Это простой вопрос, просто я все еще думаю о синтаксисе и методологии RSpec ... поэтому я немного запутался. Пожалуйста, потерпите меня ... Мне интересно, как подойти к тестированию контроллеров (и запросов и т. Д.), Когда задействован Cancan и пользователи могут иметь разные уровни авторизации.

Я читал, что одним из преимуществ Cancan является то, что он поддерживает всю аутентификацию в одной модели ... здорово! но, похоже, это сбило меня с толку ... так что я ищу совет.

Предыстория: я использую битовую маску для удержания уровня авторизации для пользователя (а-ля Railscast # 189 ). Таким образом, целочисленный столбец roles_mask будет содержать все данные для пользователя. Не уверен, что это имеет значение, но теперь вы знаете.

Я бы хотел провести несколько тестов в качестве гостя, которые должны завершиться неудачей, если гость попытается создать сообщение. Но затем в том же posts_controller_spec я хотел бы проверить, что admin и moderator могут создавать один и тот же пост. Просто не знаю, как лучше это настроить.

Итак, я должен иметь фабрику для гостевого пользователя, одну для администратора и т. Д. Перемещение @user.roles_mask = 1 в блок описания до того, как спецификации, которые я хочу для "администратора", не работает. Нет ошибок метода. Но, если я назначу role_mask на Фабрике, она работает?!? Итак, как я могу проверить разные уровни role_mask? (ноль, 0, 1, 2, 4 и т. д.)

describe PostsController do

  before(:each) do
    @user = Factory(:user)
    session[:user_id] = @user.id 
    @attr = Factory.attributes_for(:post)
  end

  describe "GET index" do
    it "assigns all posts as @posts" do
      post = @user.posts.create(@attr)
      get :index
      assigns(:posts).should eq([post])
    end
  end

  ...

  describe "POST create" do
    describe "with valid params" do
      it "creates a new Post" do
        expect {
          post :create, :post => @attr
        }.to change(Post, :count).by(1)
      end
  ...

  end

# posts_controller.rb
class PostsController < ApplicationController
  before_filter :login_required, :except => [:index, :show]
  load_and_authorize_resource
  ...
end

Factory:

Factory.define :user do |user|
  user.sequence(:email)       { |n| "foo#{n}@dummycorp.com" } 
  user.password               "foobar"
  user.password_confirmation  { |u| u.password }
  user.firstname              "foo"
  user.roles_mask   1                       # < --- remove & tests fail
                                            # < --- how to manipulate dynamically in tests
end

1 Ответ

1 голос
/ 10 августа 2011

Я думаю, что вас смущает (как и я) тот факт, что контроллер защищает доступ к ресурсам - но это все еще класс способностей, который определяет, могут ли действия контроллера выполняться на конкретном ресурсе.Получаете ли вы доступ к ресурсам через PostsController или какой-либо другой контроллер, на самом деле не должно иметь значения - вы все равно не хотите, чтобы гости делали сообщения.Если вы действительно хотите быть уверены в том, что load_and_authorize_resource вызывается в PostsController, вы можете настроить для этого один функциональный тест (гостевой пост должен провалиться) - тогда тесты способностей должны подтвердить детализацию.

 require "cancan/matchers"
describe Ability do
  before(:each) do
  end
  [Contact, Question, Provider, Organisation].each do |model|
    it "should allow any user to read a #{model.to_s} details but not delete them" do
      user= Factory(:user)
      ability = Ability.new(user)
      ability.should be_able_to(:show, model.new)
      ability.should_not be_able_to(:delete, Factory(model.to_s.underscore.to_sym))
    end
  end

  [Contact, Organisation].each do |model|
    it "should allow any admin user to delete a #{model.to_s} " do
      user= Factory(:admin)
      ability = Ability.new(user)
      ability.should be_able_to(:delete,  Factory.build(model.to_s.underscore.to_sym))
    end
  end

etc

В моем случае у меня есть пользователи-администраторы и обычные пользователи с разными способностями - я просто создал по одному для каждого из них и вызвал соответствующие методы в моделях, доступ к которым хотел ограничить.На самом деле я совсем не тестировал контроллер, потому что в моем случае в application_controller вызывается load_and_authorize_resource, поэтому один тест проверяет, что он применим ко всему приложению

...