背景
我正在尝试为我的 FastAPI 应用程序编写测试。我有一个对象
ImageRecord
,它将图像上传到S3。方法签名如下:
async def upload_image(file: UploadFile, s3_client=None) -> 'ImageRecord':
API 逻辑(即实际的
@app.post
函数)调用此方法来上传对象。我想通过将图像文件上传到
moto
- 模拟的 S3 存储桶来测试此方法。此方法在
ImageRecord
中需要一个
UploadFile
因为它是从函数调用的 - 所以我不能只传递字节。此外,我在代码中调用
file.content_type
来获取内容类型。
问题
我无法创建实际API的实例并调用它,因为为了注入模拟的S3对象,我必须直接从
ImageRecord
调用 Python 方法 - 而不是通过 HTTP 请求。但是,这意味着我需要手动创建
UploadFile
对象。以下是我创建它的方法:
contents = open("resc/valid_image.jpg", "rb").read()
upload_file = UploadFile(filename="test_image.jpg", file=io.BytesIO(contents))
但是,当我将其上传到 ImageRecord 时,我收到错误:
Invalid type for parameter ContentType, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
因为
upload_file.content_type
是
None
在真实的API代码中,当FastAPI创建文件时,
源代码
说:
请求的内容类型, 来自标头 但是我手动创建的文件没有标头,并且不接受
content_type
中的init
参数
.
TL;DR
FastAPI.UploadFile
手动创建的
content_type
没有
UploadFile
,因为必须从标头中推断出来。有没有办法用a
content_type
创建
UploadFile.content_type
实例来进行测试?或者我是否需要重构我的代码,以便它从内容推断内容类型,并一起跳过
你不需要(也不应该)手动创建
UploadFile
实例来进行测试。
UploadFile
是 FastAPI 内部使用的类,用于处理来自真实的 HTTP 请求的文件。
在你的测试中,你应该直接将字节内容传递给
upload_image
函数,并在函数内部处理内容类型检测。你可以使用 Python 的
mimetypes
模块来根据文件名或字节内容推断内容类型。
以下是更新后的代码示例:
import io
import mimetypes
# ...
async def upload_image(file: bytes, s3_client=None) -> 'ImageRecord':
"""
Uploads an image to S3.
Args:
file: The image file contents as bytes.
s3_client: An optional boto3 S3 client.
"""
content_type = mimetypes.guess_type("test_image.jpg")[0] or "application/octet-stream"
# ... your upload logic using s3_client and content_type ...
# ...
def test_upload_image():
with open("resc/valid_image.jpg", "rb") as f:
contents = f.read()
image_record = asyncio.run(upload_image(contents))
# ... your assertions ...
在这个例子中:
-
我们修改了
upload_image
函数,使其接受bytes
类型的file
参数,而不是UploadFile
。 -
我们使用
mimetypes.guess_type
函数根据文件名推断内容类型。如果无法推断,则默认为application/octet-stream
。 -
在测试函数中,我们直接读取文件内容并将其作为字节传递给
upload_image
函数。
这种方法有几个优点:
-
更简洁的测试:
你不需要创建模拟的
UploadFile
对象。 -
更贴近实际代码:
你的
upload_image
函数现在可以处理来自任何来源的字节内容,而不仅仅是UploadFile
对象。 -
更易于维护:
你不需要担心手动设置
UploadFile
对象的属性。
希望这可以帮助你编写更清晰、更有效的测试!
标签:python,fastapi,mime-types From: 78804949