Как проверить конечную точку API FastAPI, которая потребляет изображения? - PullRequest
2 голосов
/ 21 марта 2020

Я использую pytest для проверки конечной точки FastAPI, которая получает на входе изображение в двоичном формате, как в

@app.post("/analyse")
async def analyse(file: bytes = File(...)):

    image = Image.open(io.BytesIO(file)).convert("RGB")
    stats = process_image(image)
    return stats

После запуска сервера я могу вручную успешно проверить конечную точку, выполнив вызов с requests

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

url = "http://127.0.0.1:8000/analyse"

filename = "./example.jpg"
m = MultipartEncoder(
        fields={'file': ('filename', open(filename, 'rb'), 'image/jpeg')}
    )
r = requests.post(url, data=m, headers={'Content-Type': m.content_type}, timeout = 8000)
assert r.status_code == 200

Однако настройка тестов в функции вида:

from fastapi.testclient import TestClient
from requests_toolbelt.multipart.encoder import MultipartEncoder
from app.server import app

client = TestClient(app)

def test_image_analysis():

    filename = "example.jpg"

    m = MultipartEncoder(
        fields={'file': ('filename', open(filename, 'rb'), 'image/jpeg')}
        )

    response = client.post("/analyse",
                           data=m,
                           headers={"Content-Type": "multipart/form-data"}
                           )

    assert response.status_code == 200

при запуске тестов с python -m pytest, что возвращает мне

>       assert response.status_code == 200
E       assert 400 == 200
E        +  where 400 = <Response [400]>.status_code

tests\test_server.py:22: AssertionError
-------------------------------------------------------- Captured log call --------------------------------------------------------- 
ERROR    fastapi:routing.py:133 Error getting request body: can't concat NoneType to bytes
===================================================== short test summary info ====================================================== 
FAILED tests/test_server.py::test_image_analysis - assert 400 == 200

что я делаю не так?
Как правильно написать тестовую функцию test_image_analysis() с использованием файла изображения?

1 Ответ

3 голосов
/ 23 марта 2020
  1. Почему есть разница?

requests и TestClient не одинаковы во всех аспектах. TestClient обертывания requests и, возможно, как-то что-то изменит.

Если вам нужно больше копать, обратитесь к исходному коду: (FastAPI с использованием TestClient из библиотеки starlette, FYI)

https://github.com/encode/starlette/blob/master/starlette/testclient.py

Есть ли альтернативный способ:

Действительно, вы можете избавиться от MultipartEncoder, потому что requests может принимать байты файла и кодировать его в формате form-data.

изменить версию запроса:

# change it
r = requests.post(url, data=m, headers={'Content-Type': m.content_type}, timeout = 8000)

# to 
r = requests.post(url, files={"file": ("filename", open(filename, "rb"), "image/jpeg")})

Тестовая версия FastAPI:

# change
response = client.post("/analyse",
                       data=m,
                       headers={"Content-Type": "multipart/form-data"}
                       )
# to
response = client.post(
    "/analyse", files={"file": ("filename", open(filename, "rb"), "image/jpeg")}
)
...