使用 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