如何在FastAPI的Pytest测试中正确实现Mock认证?
解决FastAPI+pytest中Mock认证依赖的问题
你在测试FastAPI端点时尝试Mock认证依赖,运行测试时触发错误:
AttributeError: 'FastAPI' object has no attribute 'authenticate'
核心原因是你错误地通过app.authenticate引用认证函数,但authenticate是main.py中的独立异步函数,并非FastAPI实例app的属性。
正确的依赖覆盖方案
1. 导入原始认证函数
在测试文件中,从main模块直接导入authenticate函数:
from main import app, authenticate # 新增导入authenticate
2. 修正依赖覆盖代码
将原来的app.dependency_overrides[app.authenticate] = fake_authenticate替换为:
app.dependency_overrides[authenticate] = fake_authenticate
3. 优化Mock认证函数(可选)
原authenticate函数仅做验证逻辑(通过则继续,不通过抛异常),无返回值,所以Mock函数只需保持签名一致即可:
async def fake_authenticate( apitoken: Optional[str] = None, account: Optional[str] = None, sessionHost: Optional[str] = None ): # 模拟认证通过,无需额外逻辑 pass
完整修正后的测试代码
import os from typing import Optional from fastapi.testclient import TestClient from unittest.mock import patch, AsyncMock from main import app, authenticate # 导入authenticate from tests.mock_data import test_roles_data os.environ["TEST_ENV"] = "test" client = TestClient(app) async def fake_authenticate( apitoken: Optional[str] = None, account: Optional[str] = None, sessionHost: Optional[str] = None ): pass # 模拟认证通过 # 正确覆盖认证依赖 app.dependency_overrides[authenticate] = fake_authenticate @patch('routers.base.parse_params', new_callable=AsyncMock) @patch('services.roles.Roles.get_json', new_callable=AsyncMock) def test_roles_endpoint(mock_parse_params, mock_get_json): mock_get_json.return_value = test_roles_data mock_parse_params.return_value = ("custom_fields_value", "2023-01-01", "2023-01-31") response = client.get("/roles", headers={ 'apitoken': 'apitoken', 'account': 'account', 'sessionHost': 'sessionHost', }, params={"start_date": "2023-01-01", "end_date": "2023-01-31"}) assert response.status_code == 200 assert response.json() == test_roles_data # 可启用该断言验证返回值 # 清理环境变量 del os.environ["TEST_ENV"]
额外优化:用pytest fixture管理依赖覆盖
为避免测试间的依赖污染,建议用fixture自动管理依赖的覆盖与恢复:
import pytest @pytest.fixture(autouse=True) def override_authenticate(): # 保存原始依赖 original_dep = app.dependency_overrides.get(authenticate) # 覆盖依赖 app.dependency_overrides[authenticate] = fake_authenticate yield # 测试结束后恢复原始依赖 app.dependency_overrides[authenticate] = original_dep
内容的提问来源于stack exchange,提问作者The Dan
相关产品推荐
相关产品推荐

