Testing File uploads in Flask
I was recently writing Flask integration tests for a form that had a file upload parameter. As it turns out, is isn't as straight forward as I had thought it would be.
A basic file upload test might look like this:
def test_logo(self):
data = dict(logo=(io.BytesIO(b'test'), 'test_file.jpg')
response = self.client.post(
url_for('items.save'), data=data,
follow_redirects=True,
content_type='multipart/form-data'
)
self.assertIn(b'Your Item has been saved.', response.data)
item = Item.query.get(1)
self.assertIsNotNone(item.logo)
And that all work fine. The two key things to remember are that (in Python 3) your 'file' (in this case 'logo') needs to be a Bytes object and you need to add the content_type='multipart/form-data'
param.
Where I ran into trouble though was that I was uploading more than just the logo. In fact for the form to validate it needed a lot of other fields present.
So when I tried it again with all the required fields as part of the data
dict I got a strange error: TypeError: 'str' does not support the buffer interface.
As it turns out, there were non-string values in the data
dict I was passing though which, when combined with the content_type
caused this issue.
So to be able to run the test I had to ensure that all the fields were strings. So I simply looked over the data
dict and made all the fields strings:
def test_edit_logo(self):
# get test data dictionary
data = self.get_edit_data()
for key, value in data.items():
if not isinstance(value, str):
data[key] = str(value)
data['logo'] = (io.BytesIO(b'test'), 'test_file.jpg')
response = self.client.post(
url_for('items.save'), data=data, follow_redirects=True,
content_type='multipart/form-data'
)
self.assertIn(b'Your Item has been saved.', response.data)
item = Item.query.get(1)
self.assertIsNotNone(item.logo)
And that's it. It's a simple modification that needs to be made but the error isn't very helpful when it comes to debugging.