如何测试使用图像的 FastAPI api 端点?
How to test a FastAPI api endpoint that consumes images?
我正在使用 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()
的正确方法是什么?
您会看到不同的行为,因为 requests
和 TestClient
在每个方面都不完全相同,因为 TestClient
包装 requests
。要深入挖掘,请参阅源代码:(FastAPI
使用来自 starlette 库的 TestClient
,仅供参考)
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")}
)
我正在使用 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()
的正确方法是什么?
您会看到不同的行为,因为 requests
和 TestClient
在每个方面都不完全相同,因为 TestClient
包装 requests
。要深入挖掘,请参阅源代码:(FastAPI
使用来自 starlette 库的 TestClient
,仅供参考)
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")}
)