2013-11-28 4 views
11

GemfileКак проверить политику Pundit с помощью Minitest?

gem 'pundit', '~> 0.2.1' 

приложение/контроллеры/application_controller.rb

class ApplicationController < ActionController::Base 

    include Pundit 
    ... 

приложение/политика/application_policy.rb

class ApplicationPolicy < Struct.new(:user, :record) 
    def index? ; false;        end 
    def show? ; scope.where(id: record.id).exists?; end 
    def create? ; false;        end 
    def new? ; create?;       end 
    def update? ; false;        end 
    def edit? ; update?;       end 
    def destroy?; false;        end 
    def scope 
    Pundit.policy_scope!(user, record.class) 
    end 
end 

приложение/политика/book_policy.rb

class BookPolicy < ApplicationPolicy 

    def create? 
    record.new_record? 
    end 

    def new? 
    create?  end 

    def show? 
    record.published? || user == record.user || user.is?(:admin) 
    end 

end 

приложение/контроллеры/books_controller.rb

class BooksController < ApplicationController 
    before_action :set_book, only: [:show, :edit, :update, :destroy] 
    before_action :authenticate_user!, except: [:show] 

    after_action :verify_authorized, except: :index 
    after_action :verify_policy_scoped, only: :index 

    # GET /books/1 
    def show 
    authorize(@book) 
    end 

    # GET /books/new 
    def new 
    @book = Book.new 
    authorize(@book) 
    end 

    # POST /books 
    def create 
    @book = current_user.books.build(book_params) 
    authorize(@book) 

    if @book.save 
     redirect_to @book, notice: 'Your book was successfully created.' 
    else 
     render action: 'new' 
    end 
    end 

private 
    def set_book 
     @book = Book.find(params[:id]) 
    end 

    def book_params 
     params.require(:book).permit(:title, :description) 
    end 
end 

тест/фабрики/factories.rb

FactoryGirl.define do 

    factory :user do 
    sequence(:email) { |n| "email#{n}@x.com" } 
    password '12345678' 
    password_confirmation '12345678' 
    end 

    factory :book do 
    title 'xx' 
    user 
    end 

end 

ответ

17

Сначала попробуйте

Согласно документам Minitest я пробовал < Minitest::Test, но получил gems/minitest-4.7.5/lib/minitest/unit.rb:19:in 'const_missing': uninitialized constant MiniTest::Test (NameError), который заставил меня обнаружить, что the docs in master are for Minitest 5. Поэтому я преследовал the Minitest docs before the version 5 commit и обнаружил, что мы должны быть подклассифицированы MiniTest::Unit::TestCase.

тест/политика/book_policy_test.rb

require 'test_helper' 
class BookPolicyTest < Minitest::Test 
    ... 
end 

Вторая попытка (правильный суперкласс)

тест/политика/book_policy_test.rb

require 'test_helper' 

class BookPolicyTest < Minitest::Unit::TestCase 

    def test_new 
    user = FactoryGirl.create(:user) 
    book_policy = BookPolicy.new(user, Book.new) 
    assert book_policy.new? 
    end 

    def test_create 
    book = FactoryGirl.create(:book) 
    book_policy = BookPolicy.new(book.user, book) 
    assert !book_policy.create? 
    end 

end 

Refactor один (создать «разрешение»)

тест/политика/book_policy_test.rb

require 'test_helper' 

class BookPolicyTest < Minitest::Unit::TestCase 

    def test_new 
    user = FactoryGirl.create(:user) 
    assert permit(user, Book.new, :new) 
    end 

    def test_create 
    book = FactoryGirl.create(:book) 
    assert !permit(book.user, book, :create) 
    end 

private 

    def permit(current_user, record, action) 
     self.class.to_s.gsub(/Test/, '').constantize.new(current_user, record).public_send("#{action.to_s}?") 
    end 

end 

реорганизовывать два (класс СОЗДАТЬ 'Policytest')

тест/test_helper.rb

class PolicyTest < Minitest::Unit::TestCase 

    def permit(current_user, record, action) 
    self.class.to_s.gsub(/Test/, '').constantize.new(current_user, record).public_send("#{action.to_s}?") 
    end 

end 

тест/политика/book_policy_test.rb

require 'test_helper' 

class BookPolicyTest < PolicyTest 

    def test_new 
    user = FactoryGirl.create(:user) 
    assert permit(user, Book.new, :new) 
    end 

    def test_create 
    book = FactoryGirl.create(:book) 
    assert !permit(book.user, book, :create) 
    end 

end 

Refactor три (создать 'запретить' метод)

тест/test_helper.гь

class PolicyTest < Minitest::Unit::TestCase 

    def permit(current_user, record, action) 
    self.class.to_s.gsub(/Test/, '').constantize.new(current_user, record).public_send("#{action.to_s}?") 
    end 

    def forbid(current_user, record, action) 
    !permit(current_user, record, action) 
    end 

end 

тест/политика/book_policy_test.rb

require 'test_helper' 

class BookPolicyTest < PolicyTest 

    def test_new 
    user = FactoryGirl.create(:user) 
    assert permit(user, Book.new, :new) 
    end 

    def test_create 
    book = FactoryGirl.create(:book) 
    assert forbid(book.user, book, :create) 
    end 

end 

Добавить полный набор тестов политик

require 'test_helper' 

class BookPolicyTest < PolicyTest 

    def test_new 
    assert permit(User.new, Book.new, :new) 

    book = FactoryGirl.create(:book) 
    assert forbid(book.user, book, :new) 
    end 

    def test_create 
    assert permit(User.new, Book.new, :create) 

    book = FactoryGirl.create(:book) 
    assert forbid(book.user, book, :create) 
    end 

    def test_show 
    # a stranger should be able to see a published book 
    stranger = FactoryGirl.build(:user) 
    book = FactoryGirl.create(:book, published: true) 
    refute_equal stranger, book.user 
    assert permit(stranger, book, :show) 

    # but not if it's NOT published 
    book.published = false 
    assert forbid(stranger, book, :show) 

    # but the book owner still should 
    assert permit(book.user, book, :show) 

    # and so should the admin 
    admin = FactoryGirl.build(:admin) 
    assert permit(admin, book, :show) 
    end 

end 
2

Строительство на ответ user664833, я использовать следующие для проверки policy_scope Пандит в :

def permit_index(user, record) 
    (record.class.to_s + 'Policy::Scope').constantize.new(user, record.class).resolve.include?(record) 
end 

Например:

assert permit_index(@book.user, @book) 
5

Я создал камень для тестирования пандита с MiniTest называется policy-assertions. Вот как выглядит ваш тест.

class ArticlePolicyTest < PolicyAssertions::Test 
    def test_index_and_show 
    assert_permit nil, Article 
    end 

    def test_new_and_create 
    assert_permit users(:staff), Article 
    end 

    def test_destroy 
    refute_permit users(:regular), articles(:instructions) 
    end 
end 
+0

Кевин - ты жизнь заставка. Судя по красноречивому и подробному README, он выглядит как очень хорошо сделанный драгоценный камень. Попытайтесь попробовать сейчас. – DannyB

3

Пандит теперь обеспечивает Pundit#authorize (https://github.com/elabs/pundit/pull/227). Так метод разрешения user664833 может быть обновлен, как показано ниже:

def permit(current_context, record, action) 
    Pundit.authorize(current_context, record, action) 
rescue Pundit::NotAuthorizedError 
    false 
end 
Смежные вопросы