[英]How to test Pundit policies with 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
測試/工廠/工廠.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
根據Minitest
文檔,我嘗試了< Minitest::Test
,但得到gems/minitest-4.7.5/lib/minitest/unit.rb:19:in 'const_missing': uninitialized constant MiniTest::Test (NameError)
這導致我發現master 中的文檔適用於 Minitest 5 。 所以我在版本 5 提交之前搜索了 Minitest 文檔,發現我們應該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
我創建了一個 gem,用於使用名為policy-assertions 的minitest 測試專家。 這是您的測試的樣子。
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
Pundit 現在提供Pundit#authorize
( https://github.com/elabs/pundit/pull/227 )。 所以 user664833 的 permit 方法可以更新如下:
def permit(current_context, record, action)
Pundit.authorize(current_context, record, action)
rescue Pundit::NotAuthorizedError
false
end
基於 user664833 的回答,我使用以下內容來測試 Pundit 的 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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.