2013-11-28 17 views
11

GemfileCome testare le politiche di Pundit con Minitest?

gem 'pundit', '~> 0.2.1' 

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base 

    include Pundit 
    ... 

app/politiche/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 

app/politiche/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 

app/controllers/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 

test/fabbriche/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 

risposta

17

primo tentativo

Come per i documenti Minitest ho provato < Minitest::Test, ma ho ottenuto gems/minitest-4.7.5/lib/minitest/unit.rb:19:in 'const_missing': uninitialized constant MiniTest::Test (NameError) che mi ha portato a scoprire che the docs in master are for Minitest 5. Quindi ho dato la caccia allo the Minitest docs before the version 5 commit e ho scoperto che dovremmo creare una sottoclasse di MiniTest::Unit::TestCase.

prova/politiche/book_policy_test.rb

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

secondo tentativo (corretta superclasse)

test/politiche/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 uno (creare metodo 'permesso')

test/politiche/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 

refactoring due (creare 'Policytest' classe)

test/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 

test/politiche/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 tre (creare il metodo 'vietare')

test/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 

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

end 

test/politiche/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 

Aggiungere serie completa di test di politica

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

edificio sulla risposta di user664833 Io uso il seguente per testare policy_scope di Pundit :

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

Ad esempio:

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

ho creato un gioiello per il test esperto con Minitest chiamato policy-assertions. Ecco come si presenta il tuo test.

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

Kevin - sei un risparmiatore di vita. A giudicare dal README eloquente e dettagliato, sembra una gemma molto ben fatta. Andando a fare un tentativo in questo momento. – DannyB

3

Pundit offre ora Pundit#authorize (https://github.com/elabs/pundit/pull/227). Quindi il metodo di autorizzazione di user664833 può essere aggiornato come segue:

def permit(current_context, record, action) 
    Pundit.authorize(current_context, record, action) 
rescue Pundit::NotAuthorizedError 
    false 
end