[英]setting up minitest with Devise with refactoring test_helper
Rails 7 應用程序使用 devise 進行身份驗證。
fixture(模型測試通過所有類):
one:
email: 'me@mail.co'
encrypted_password: <%= User.new.send(:password_digest, '12345678')
test_helper 試圖在實際的 controller 測試中將登錄和操作過程重構為短的一行 ( test_access
)
require 'simplecov'
SimpleCov.start 'rails'
ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
require "rails/test_help"
require 'webmock/minitest'
require 'barby/outputter/png_outputter'
require 'barby/barcode/ean_13'
class ActiveSupport::TestCase
fixtures :all
include Devise::Test::IntegrationHelpers
include Warden::Test::Helpers
parallelize(workers: :number_of_processors)
def log_in(user)
if integration_test?
login_as(user, :scope => :user)
else
sign_in(user)
end
end
class Minitest::Test
def setup
@one = users(:one)
end
end
private
def test_access(user, action)
get '/users/sign_in'
puts user.inspect
sign_in user
# puts user_signed_in?
# puts current_user.manager?
puts user.manager?
post user_session_url
follow_redirect!
puts action
get action
assert_response :success
end
和 controller_test(目前處於中間重構級別,因為該方法應該擴展到一組用戶)
require "test_helper"
class LokationsControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
setup do
@users_allowed = [ @one ]
@actions = [dummy_lokations_url]
end
test "should get dummy" do
@actions.each do |action|
test_access(@one, action)
assert_response :success
end
end
問題是似乎沒有辦法驗證用戶是否登錄,盡管包含 devise 集成助手。 控制台中的output指向正確的值,但結果與應該應用的方法相反
#<User id: 760812109, email: [...]>
true
http://www.example.com/lokations/dummy
[...]
Expected response to be a <2XX: success>, but was a <302: Found> redirect to <http://www.example.com/>
Response body: <html><body>You are being <a href="http://www.example.com/">redirected</a>.</body></html>
因為應用於操作的 before_action 方法指定
def index_manager
if user_signed_in? && current_user.manager?
else
redirect_to root_path and return
end
end
上面哪里錯了? (我一直懷疑可能缺少某些東西,因為過去已成功遵循此模式)
抱歉,但這不是一個好的/可接受的重構。
永遠不要設置密碼摘要。 這應該只被加密密碼的底層系統知道。 您的代碼和測試甚至不應該知道它的存在。 您的代碼應該只使用明文設置密碼屬性。
這些是集成而不是 controller 測試。 Controller 測試是遺留應用程序中使用的ActionController::TestCase
的子類。 不應使用它們。 雖然這看起來像是在挑剔,但您只是將自己和他人混為一談而感到困惑。
避免將一堆垃圾修補到ActiveSupport::TestCase
或更糟的Minitest::Test
中。 如果你必須 monkeypatch 那么將你的方法寫在一個模塊中並包含它以便堆棧跟蹤指向那里。 但是在 class 層次結構中的正確級別進行。 例如,將用於集成和系統測試的幫助程序分開,並將它們包含到ActionDispatch::IntegrationTest
和ActionDispatch::SystemTest
中,而不是污染所有測試。
如果您需要添加很多額外的行為,請不要重新打開 class。而是創建您自己的測試 class,它繼承自ActionDispatch::IntegrationTest
並讓您的測試子類化它。
如果您有要在多個測試中重用的代碼,例如測試設置,請使用可以包含在實際需要的地方的模塊。
test_access
不屬於樹上的共享子類。 這屬於實際集成測試,涵蓋您的身份驗證系統流程或特定資源已正確授權。
Devise 是一個認證系統(誰是用戶?)——但你在這里做的是授權(誰能做什么?)。 Devise 除了阻止未經身份驗證的用戶訪問外,不提供任何類型的授權。 也不應該(參見SRP )。
index_manager
方法不是實現授權的好方法。 如果您想重新發明輪子,請確保引發異常並使用rescue_from
以便回調鏈停止,這樣您就不會重復自己。 您可能需要查看現有系統,例如 CanCanCan 和 Pundit。
你在這里真正想要的更像是:
class AuthorizationError < StandardError
end
class ApplicationController
before_action :authenticate_user! # use an opt-out secure by default setup.
rescue_from AuthorizationError, with: :deny_access
private
def authorize_manager!
unless current_user.manager?
raise AuthorizationError.new("You need to be a manager to access this resource")
end
end
def deny_access(exception)
redirect_to root_path, error: exception.message
end
end
module AuthorizationIntegrationHelpers
def assert_denies_access
follow_redirect!
assert_current_path root_path
# ...
end
end
class FoosFlowTest < ActionDispatch::IntegrationTest
include AuthorizationIntegrationHelpers
include Warden::Test::Helpers
test "should not be accessable to non-managers" do
login_as(users(:one))
get '/foos'
assert_denies_access
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.