FastAPI与Pytest测试POST接口遇422错误,如何正确传参?
问题:FastAPI OAuth2登录接口测试报422错误
尝试使用FastAPI的TestClient测试/login相关的/token API,向POST接口传递JSON格式的username和password时,出现422错误,提示username和password字段为必填项。
API实现代码
@router.post('/token', response_model=schemas.Token) async def login(user_credentials: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): """ Login to the system with (Email | Username | Contact) """ user = db.query(models.User).filter( (models.User.email == user_credentials.username) | (models.User.username == user_credentials.username) | (models.User.contact == user_credentials.username) ).first() if not user: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Invalid Credentials" ) if not utils.verify_pwd(user_credentials.password, user.password): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Invalid Credentials" ) access_token = oauth2.create_access_token(data={'user_id': user.id}) return {"access_token": access_token, "token_type": "bearer"}
测试代码
from fastapi.testclient import TestClient from ..main import app client = TestClient(app) def test_auth_token(get_client: TestClient): client = get_client.post('/token', json={"username": "admin", "password": "1234567890"}) assert client.status_code == 200
错误信息
(venv) ✘ genex@Genexs-MacBook-Pro: pytest -s ================================================================================== test session starts =================================================================================== platform darwin -- Python 3.10.8, pytest-7.2.1, pluggy-1.0.0 rootdir: /Users/genex/Desktop/basha-bari plugins: asyncio-0.20.3, anyio-3.6.2 asyncio: mode=strict collected 1 item apps/utility/test_utility_routers.py {'detail': [{'loc': ['body', 'username'], 'msg': 'field required', 'type': 'value_error.missing'}, {'loc': ['body', 'password'], 'msg': 'field required', 'type': 'value_error.missing'}]} F ======================================================================================== FAILURES ======================================================================================== ____________________________________________________________________________________ test_auth_token _____________________________________________________________________________________ def test_auth_token(): result = client.post('/token', json={"username": "admin", "password": "1234567890"}) print(result.json()) > assert result.status_code == 200 E assert 422 == 200 E + where 422 = <Response [422 Unprocessable Entity]>.status_code apps/utility/test_utility_routers.py:12: AssertionError ================================================================================ short test summary info ================================================================================= FAILED apps/utility/test_utility_routers.py::test_auth_token - assert 422 == 200 =================================================================================== 1 failed in 1.06s ====================================================================================
解决方法
直接修改测试代码(适配现有接口)
你的接口使用了OAuth2PasswordRequestForm作为请求依赖,这个类默认只接收**表单格式(application/x-www-form-urlencoded)**的请求体,不支持JSON格式。因此测试时需要把json参数换成data参数传递数据:
def test_auth_token(get_client: TestClient): # 用data参数传递表单格式数据,而非json response = get_client.post('/token', data={"username": "admin", "password": "1234567890"}) assert response.status_code == 200
可选:修改接口支持JSON格式(如果需要)
如果希望接口同时支持JSON和表单格式,可以自定义一个Pydantic模型替代OAuth2PasswordRequestForm,或者结合两种格式的处理逻辑:
from pydantic import BaseModel class LoginRequest(BaseModel): username: str password: str @router.post('/token', response_model=schemas.Token) async def login( form_data: OAuth2PasswordRequestForm = Depends(), json_data: LoginRequest = None, db: Session = Depends(get_db) ): # 优先取JSON数据,没有则用表单数据 username = json_data.username if json_data else form_data.username password = json_data.password if json_data else form_data.password # 后续逻辑保持不变 user = db.query(models.User).filter( (models.User.email == username) | (models.User.username == username) | (models.User.contact == username) ).first() # ... 其余验证和生成token逻辑
这样修改后,测试时既可以用data参数传表单,也可以用json参数传JSON数据。
内容的提问来源于stack exchange,提问作者Fahad Md Kamal
相关产品推荐
相关产品推荐

