简体   繁体   English

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

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

I have an endpoint in fastapi app that does the following:我在 fastapi 应用程序中有一个端点,它执行以下操作:

  1. Checks if the file is a text file ( .txt )检查文件是否为文本文件 ( .txt )
  2. Uploads the file to the S3 bucket将文件上传到 S3 存储桶

The codes:代码:

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)

The code where the check is done检查完成的代码

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.'}

I want to test this endpoint to see if the file being uploaded is a text file or not.我想测试这个端点,看看上传的文件是否是文本文件。

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

When I run this code, I get the following error当我运行此代码时,出现以下错误

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

What is the mistake I am doing?我在做什么错误?

The HTTPException in the FastAPI app will not propagate out, FastAPI will catch it and use it to return an HTTP error response (otherwise, raising an exception would crash your entire app). HTTPException应用程序中的 HTTPException 不会传播出去,FastAPI 将捕获它并使用它返回 HTTP 错误响应(否则,引发异常会导致整个应用程序崩溃)。

Since what TestClient is doing is essentially just calling your API as any other client would, what you want to do is test that you get the correct error response.由于TestClient所做的基本上只是像任何其他客户端一样调用您的 API,因此您要做的是测试您是否获得了正确的错误响应。 Something along the lines of类似的东西

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"}

I guess there's a problem with the file name, in your endpoint upload_file is expected, but in your test, you're passing an object with file name.我猜文件名有问题,在您的端点upload_file是预期的,但在您的测试中,您传递了一个带有file名的 object。 So you get 422 Unprocessable Entity exception.所以你得到422 Unprocessable Entity异常。 You can easily debug it yourself:您可以轻松地自己调试它:

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

So, to fix your problem pass the expected file name:因此,要解决您的问题,请传递预期的文件名:

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

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

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