You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastAPI单元测试中模拟带Authorization头的Request对象?

解决方案:正确模拟带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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:32:42