如何在FastAPI单元测试中模拟带Authorization头的Request对象?
针对你遇到的Authorization头缺失导致的KeyError问题,有两种主流解决方式,根据测试场景选择即可:
方法1:使用TestClient发送带Authorization头的请求(推荐)
如果是测试整个接口的端到端行为,直接用fastapi.testclient.TestClient发送请求时携带头即可,无需手动模拟Request对象:
from fastapi.testclient import TestClient from app.main import app # 导入你的FastAPI应用实例 client = TestClient(app) def test_change_password(): response = client.put( "/account/change-password", json={"old_password": "old_pass", "new_password": "new_pass"}, headers={"Authorization": "Bearer test_access_token"} ) assert response.status_code == 200 assert response.json() == {"detail": "Password changed"}
这种方式完全模拟真实HTTP请求流程,TestClient会自动构造包含指定头的Request实例。
方法2:手动模拟Request对象(单独测试接口函数)
如果是直接测试change_password函数本身,可通过以下两种方式构造带Authorization头的Request:
方式A:构造真实的Starlette Request实例
from starlette.requests import Request from starlette.datastructures import Headers from app.account import change_password # 导入你的接口函数 from app.schemas import ChangePasswordRequest def test_change_password_function(): # 构造包含Authorization的Headers headers = Headers({"Authorization": "Bearer test_access_token"}) # 构建Request所需的scope字典 req = Request( scope={ "type": "http", "headers": headers.raw, "method": "PUT", "path": "/account/change-password", "query_string": b"", } ) # 构造请求体实例 request_data = ChangePasswordRequest(old_password="old_pass", new_password="new_pass") # 模拟依赖项和业务方法 from unittest.mock import Mock, patch with patch("app.account.cognito.auth_required", return_value=Mock()): with patch("app.account.user_management_service.change_password") as mock_change_pwd: response = change_password(req, request_data) assert response.detail == "Password changed" mock_change_pwd.assert_called_once_with( old_password="old_pass", new_password="new_pass", access_token="test_access_token" )
方式B:用Mock快速模拟Request对象
from unittest.mock import Mock from app.account import change_password from app.schemas import ChangePasswordRequest def test_change_password_mock(): # 模拟Request对象,直接设置headers属性 mock_req = Mock() mock_req.headers = {"Authorization": "Bearer test_access_token"} request_data = ChangePasswordRequest(old_password="old_pass", new_password="new_pass") # 模拟依赖项和业务方法 from unittest.mock import patch with patch("app.account.cognito.auth_required", return_value=Mock()): with patch("app.account.user_management_service.change_password") as mock_change_pwd: response = change_password(mock_req, request_data) assert response.detail == "Password changed" mock_change_pwd.assert_called_once_with( old_password="old_pass", new_password="new_pass", access_token="test_access_token" )
额外优化建议
原代码中直接通过req.headers["Authorization"]取值会在头缺失时抛出未处理的KeyError,建议添加容错判断:
token_header = req.headers.get("Authorization") if not token_header or not token_header.startswith("Bearer "): raise HTTPException(401, "Invalid or missing Authorization header") token = token_header.split('Bearer ')[1]
这样能返回更友好的401错误,避免未捕获的异常。
内容的提问来源于stack exchange,提问作者Meitaiyang
相关产品推荐
相关产品推荐

