Background
I am trying to write tests for my FastAPI application. I have an object, ImageRecord
, which uploads an image to S3. Here’s the method signature:
async def upload_image(file: UploadFile, s3_client=None) -> 'ImageRecord':
This method is called by the API logic (i.e. the actual @app.post
function) to upload an object. I want to test this method by uploading an image file to moto
– so a mocked S3 bucket. This method, in ImageRecord
, expects an UploadFile
because it is called from the function – so I can’t just pass in the bytes. Additionally, I call file.content_type
in my code to get the content type.
The Issue
I can’t create an instance of my actual API and call it because, in order to inject the mocked S3 object, I have to call the Python method from ImageRecord
directly – not via a HTTP request. However, this means that I need to create the UploadFile
object manually. Here is how I am creating it:
contents = open("resc/valid_image.jpg", "rb").read()
upload_file = UploadFile(filename="test_image.jpg", file=io.BytesIO(contents))
However, when I upload it to ImageRecord, I get the error:
Invalid type for parameter ContentType, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
Because upload_file.content_type
is None
. In real API code, when FastAPI creates the file, the source code says:
The content type of the request, from the headers
But my manually created file has no headers, and does not accept acontent_type
argument ininit
.
TL;DR
A manually created FastAPI.UploadFile
has no content_type
, because that must be inferred from the headers. Is there any way to create an UploadFile
instance with a content_type
for tests? Or do I need to refactor my code so that it infers the content type from the contents, and skips UploadFile.content_type
alltogether?
MrDeveloper is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.