提问人:The Dan 提问时间:11/16/2023 最后编辑:The Dan 更新时间:11/18/2023 访问量:51
如何在pytest中为FastAPI应用正确实现模拟认证?
How to Correctly Implement Mocked Authentication in Pytest for FastAPI Application?
问:
我正在使用 FastAPI 和 pytest 来测试我的应用程序中的端点。我需要模拟身份验证依赖项,但我在正确实现它方面面临挑战。我的主要目标是确保正确设置模拟身份验证,以便我的测试可以在不触及实际身份验证逻辑的情况下运行。
我的pytest代码
import os
from typing import Optional
from fastapi.testclient import TestClient
from unittest.mock import patch, AsyncMock
from main import app
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
):
return {
'apitoken': 'apitoken',
'account': 'account',
'sessionHost': 'sessionHost',
}
app.dependency_overrides[app.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
# Reset the environment variable after tests
del os.environ["TEST_ENV"]
但是,当我运行测试时,出现以下错误:
AttributeError: 'FastAPI' object has no attribute 'authenticate'
此错误发生在我尝试使用模拟身份验证函数覆盖依赖关系的行处。我确信该函数存在于我的主应用程序中,并且在我的路由中正确使用。authenticate
我正在寻找有关如何在我的 FastAPI 应用程序的 pytest 设置中正确模拟身份验证的指导。实现此目的的正确方法是什么,以便我的终结点测试可以绕过实际的身份验证逻辑?
其他信息
/main.py
async def authenticate(
apitoken: Optional[str] = Header(""),
account: Optional[str] = Header(""),
sessionHost: Optional[str] = Header(""),
):
print(sessionHost)
if (
sessionHost
and sessionHost[-20:] == "mydomain-staging.com"
or sessionHost == "https://apistaging.mydomain.com"
):
url = sessionHost + "/api/jml/templates"
else:
url = PF_API_URL + "/jml/templates"
print(url)
params = {"per_page": 1, "page": 1}
accept = "application/vnd.mydomain+json;version=2"
auth_headers = {
"content_type": "application/json",
"accept": accept,
"account": account,
"apitoken": apitoken,
}
r = await session.get(url, headers=auth_headers, params=params, timeout=30)
if r.status_code != 200:
raise HTTPException(status_code=401, detail="Unauthorized")
app.token_cache[apitoken] = {
"account": account,
"ts": datetime.now(),
}
app.include_router(
stats.router,
dependencies=[Depends(authenticate)],
responses={404: {"description": "Not found"}},
)
/路由器/stats.py
@router.get("/roles")
async def roles(
request: Request,
account: str = Header(...),
start_date: str = None,
end_date: str = None,
profile_id: int = 0,
):
custom_fields, start_date, end_date = parse_params(
request, start_date, end_date
)
new_role = Roles(
account, start_date, end_date, profile_id, custom_fields=custom_fields
)
try:
await new_role.setup()
result = await new_role.get_json()
except NoDataException:
result = {"Error": "No Data"}
return result
答:
0赞
Yurii Motov
11/16/2023
#1
在测试模块中,导入依赖函数并使用其名称覆盖依赖关系:
from main import app, authenticate
...
app.dependency_overrides[authenticate] = fake_authenticate
评论
0赞
The Dan
11/16/2023
请详细说明一下
0赞
Yurii Motov
11/16/2023
在测试模块中,导入依赖函数 () from 并使用其名称覆盖依赖关系,而不是authenticate
main.py
app.authenticate
0赞
The Dan
11/16/2023
进行了更改,但它仍然给了我 404
0赞
The Dan
11/16/2023
tests/test_stats_endpoints.py::test_roles_endpoint - 断言 404 == 200
0赞
Yurii Motov
11/16/2023
问题似乎出在路由函数(异步 def 角色)的实现上,而不是在授权上。尝试在此函数的开头添加“return {}”
评论
/roles