簡體   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