繁体   English   中英

测试使用 FastAPI + pytest 上传文本文件的端点时出错

[英]Error testing an endpoint that uploads a text file using FastAPI + pytest

我在 fastapi 应用程序中有一个端点,它执行以下操作:

  1. 检查文件是否为文本文件 ( .txt )
  2. 将文件上传到 S3 存储桶

代码:

upload.py

from app.services.file_upload import file_uploader
from fastapi import APIRouter, File, UploadFile

router = APIRouter(
    prefix="/upload-file",
    tags=["Upload File"],
    responses={
        200: {'description': 'Success'},
        400: {'description': 'Bad Request'},
        422: {'description': 'Unprocessable Entity'},
        500: {'description': 'Internal Server Error'}
    }
)

@router.post('/')
def upload_file(upload_file: UploadFile = File(
        ...,
        description='Upload file'
)):
    filename = upload_file.filename
    file_content = upload_file.file
    return file_uploader(filename, file_content)

检查完成的代码

file_upload.py

import io
from typing import BinaryIO, Dict

import boto3
from app.core.config import settings
from fastapi import HTTPException

def file_uploader(filename: str, file_content: BinaryIO) -> Dict[str, str]:
    if not filename.lower().endswith('.txt'):
        raise HTTPException(status_code=422, detail='Only .txt file allowed')

    s3 = boto3.client('s3')
    file_content = io.BytesIO(file_content.read())
    s3.upload_fileobj(file_content, settings.S3_BUCKET, filename)
    return {'message': 'File uploaded.'}

我想测试这个端点,看看上传的文件是否是文本文件。

conftest.py

from typing import Generator

import pytest
from app.main import app
from fastapi.testclient import TestClient


@pytest.fixture(scope="module")
def client() -> Generator:
    with TestClient(app) as c:
        yield c

test_upload.py

import pytest
from fastapi import HTTPException
from fastapi.testclient import TestClient

def test_upload_file(client: TestClient):
    test_file = 'test_file.docx'
    files = {'file': ('test_file.docx', open(test_file, 'rb'))}
    with pytest.raises(HTTPException) as err:
        client.post('/api/v1/upload-file/', files=files)
    assert err.value.status_code == 422

当我运行此代码时,出现以下错误

FAILED app/tests/api/v1/test_upload.py::test_upload_file - Failed: DID NOT RAISE <class 'fastapi.exceptions.HTTPException'>

我在做什么错误?

HTTPException应用程序中的 HTTPException 不会传播出去,FastAPI 将捕获它并使用它返回 HTTP 错误响应(否则,引发异常会导致整个应用程序崩溃)。

由于TestClient所做的基本上只是像任何其他客户端一样调用您的 API,因此您要做的是测试您是否获得了正确的错误响应。 类似的东西

import pytest
from fastapi.testclient import TestClient

def test_upload_file(client: TestClient):
    test_file = 'test_file.docx'
    files = {'file': ('test_file.docx', open(test_file, 'rb'))}
    response = client.post('/api/v1/upload-file/', files=files)
    assert response.status_code == 422
    assert response.json() == {"detail": "Only .txt file allowed"}

我猜文件名有问题,在您的端点upload_file是预期的,但在您的测试中,您传递了一个带有file名的 object。 所以你得到422 Unprocessable Entity异常。 您可以轻松地自己调试它:

response = client.post('/api/v1/upload-file/', files=files)
print(response.json()) # {'detail': [{'loc': ['body', 'upload_file'], 'msg': 'field required', 'type': 'value_error.missing'}]}

因此,要解决您的问题,请传递预期的文件名:

files = {'upload_file': ('test_file.docx', open(test_file, 'rb'))}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM