使用 AsyncClient 的 pytest 快速 API 在 post 上给出 422?
Fast API with pytest using AsyncClient gives 422 on post?
我正在尝试使用 pytest 通过 httpx.AsynClient[= 向 api 发送请求21=]
@pytest.mark.anyio
async def test_device_create_with_data(self, client, random_uuid):
device_create = DeviceCreateFactory.build(subId=random_uuid)
json = device_create.json(by_alias=True)
response = await client.post("/device", json=json)
assert response.status_code == 200
客户端夹具:
from httpx import AsyncClient
@pytest.fixture(scope="session")
async def client():
async with AsyncClient(
app=app,
base_url="http://test/api/pc",
headers={"Content-Type": "application/json"}
) as client:
yield client
API 端点:
@device_router.post("/device", response_model=CommonResponse)
async def create_device(device: DeviceCreate):
_, err = await crud_device.create_device(device)
if err:
return get_common_response(400, err)
return get_common_response(200, "ok")
模式:
class DeviceBase(BaseModel):
device_id: StrictStr = Field(..., alias='deviceId')
device_name: StrictStr = Field(..., alias='deviceName')
device_type: StrictStr = Field(..., alias='deviceType')
age_mode: AgeModeType = Field(..., alias='ageMode')
class Config:
allow_population_by_field_name = True
validate_all = True
validate_assignment = True
class DeviceCreate(DeviceBase):
sub_id: StrictStr = Field(..., alias='subId')
class Config:
orm_mode = True
工厂:
from pydantic_factories import ModelFactory
from app.core.schemas.device import DeviceCreate
class DeviceCreateFactory(ModelFactory):
__model__ = DeviceCreate
我收到一个 422 错误,响应内容如下:
"message":"bad request","details":{"deviceId":"field required","deviceName":"field required","deviceType":"field required","ageMode":"field required","subId":"field required"}
然后我检查了正在发送的请求的数据并得到:
b'"{\"deviceId\": \"de\", \"deviceName\": \"\", \"deviceType\": \"\", \"ageMode\": \"child\", \"subId\": \"11aded61-9966-4be1-a781-387f75346811\"}"'
看似一切正常,但问题出在哪里呢?
我已经尝试检查 422 异常处理程序中的请求数据
我做了:
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
print(await request.json())
response = validation_error_response(exc)
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder(response.dict())
)
但是打印后的代码无法访问,因为 await request.json()
永远不会结束并永远运行以尝试打印请求 json
有没有办法解决这个问题?
感谢您的任何建议!
P.S.
python版本:3.8.9
快速api 版本: 0.68.1
httpx 版本:0.21.1
您将您的内容双重编码为 JSON - 您都要求将其作为 JSON 字符串返回,然后告诉您的请求方法将其编码为 JSON 第二次。 json=
作为客户端方法的参数 将给定数据 转换为 JSON - 它不期望已经序列化 JSON.
您可以在请求字符串中看到这一点,因为它以 "
开头,而不是您期望的 {
:
b'"{\
^
而是围绕字典构建您的模型 - 或者像我希望在测试中那样 - 手动构建请求,这样您就可以测试您想象的实际请求的样子。
您可以像对 Pydantic 模型使用 json
一样使用 dict
:
device_create = DeviceCreateFactory.build(subId=random_uuid)
response = await client.post("/device", json=device_create.dict(by_alias=True))
assert response.status_code == 200
我正在尝试使用 pytest 通过 httpx.AsynClient[= 向 api 发送请求21=]
@pytest.mark.anyio
async def test_device_create_with_data(self, client, random_uuid):
device_create = DeviceCreateFactory.build(subId=random_uuid)
json = device_create.json(by_alias=True)
response = await client.post("/device", json=json)
assert response.status_code == 200
客户端夹具:
from httpx import AsyncClient
@pytest.fixture(scope="session")
async def client():
async with AsyncClient(
app=app,
base_url="http://test/api/pc",
headers={"Content-Type": "application/json"}
) as client:
yield client
API 端点:
@device_router.post("/device", response_model=CommonResponse)
async def create_device(device: DeviceCreate):
_, err = await crud_device.create_device(device)
if err:
return get_common_response(400, err)
return get_common_response(200, "ok")
模式:
class DeviceBase(BaseModel):
device_id: StrictStr = Field(..., alias='deviceId')
device_name: StrictStr = Field(..., alias='deviceName')
device_type: StrictStr = Field(..., alias='deviceType')
age_mode: AgeModeType = Field(..., alias='ageMode')
class Config:
allow_population_by_field_name = True
validate_all = True
validate_assignment = True
class DeviceCreate(DeviceBase):
sub_id: StrictStr = Field(..., alias='subId')
class Config:
orm_mode = True
工厂:
from pydantic_factories import ModelFactory
from app.core.schemas.device import DeviceCreate
class DeviceCreateFactory(ModelFactory):
__model__ = DeviceCreate
我收到一个 422 错误,响应内容如下:
"message":"bad request","details":{"deviceId":"field required","deviceName":"field required","deviceType":"field required","ageMode":"field required","subId":"field required"}
然后我检查了正在发送的请求的数据并得到:
b'"{\"deviceId\": \"de\", \"deviceName\": \"\", \"deviceType\": \"\", \"ageMode\": \"child\", \"subId\": \"11aded61-9966-4be1-a781-387f75346811\"}"'
看似一切正常,但问题出在哪里呢?
我已经尝试检查 422 异常处理程序中的请求数据 我做了:
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
print(await request.json())
response = validation_error_response(exc)
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder(response.dict())
)
但是打印后的代码无法访问,因为 await request.json()
永远不会结束并永远运行以尝试打印请求 json
有没有办法解决这个问题? 感谢您的任何建议!
P.S.
python版本:3.8.9
快速api 版本: 0.68.1
httpx 版本:0.21.1
您将您的内容双重编码为 JSON - 您都要求将其作为 JSON 字符串返回,然后告诉您的请求方法将其编码为 JSON 第二次。 json=
作为客户端方法的参数 将给定数据 转换为 JSON - 它不期望已经序列化 JSON.
您可以在请求字符串中看到这一点,因为它以 "
开头,而不是您期望的 {
:
b'"{\
^
而是围绕字典构建您的模型 - 或者像我希望在测试中那样 - 手动构建请求,这样您就可以测试您想象的实际请求的样子。
您可以像对 Pydantic 模型使用 json
一样使用 dict
:
device_create = DeviceCreateFactory.build(subId=random_uuid)
response = await client.post("/device", json=device_create.dict(by_alias=True))
assert response.status_code == 200