2013-11-28 29 views
11

的Gemfile如何使用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 

重構一個(創建'許可'方法)

測試/策略/ 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 

重構兩(創建 '策略測試' 類)

測試/ 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 

重構的三(創建 '禁止' 的方法)

測試/ 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 

測試/政策/ 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

凱文 - 你是一個救星。通過雄辯和詳細的自述文件來判斷,它看起來像一個非常完美的寶石。現在就試試看。 – DannyB

3

Pundit現在提供Pundit#authorizehttps://github.com/elabs/pundit/pull/227)。 因此,user664833的許可方法可以更新如下:

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