I recently spent a few days trying to track down a bug in Review Board with our unit tests. Basically, unit tests involving uploading a file to a models.ImageField would fail with a validation error specifying that the file wasn’t an image. This worked fine when actually using the application, just not during unit tests.
The following code would cause this problem. (Note that this isn’t actual code, just a demonstration.)
# myapp/models.py from django.db import models class MyModel(models.Model): image = models.ImageField()
# myapp/forms.py from django import forms from myapp.models import MyModel class UploadImageForm(forms.Form): image_path = forms.ImageField(required=True) def create(self, file): mymodel = MyModel() mymodel.save_image_file(file.name, file, save=True) return mymodel
# myapp/views.py from myapp.forms import UploadImageForm def upload(request): form = UploadImageForm(request.POST, request.FILES) if not form.is_valid(): # Return some error pass # Return success
# myapp/tests.py from django.test import TestCase class MyTests(TestCase): def testImageUpload(self): f = open("testdata/image.png", "r") resp = self.client.post("/upload/", { 'image_path': f, }) f.close()
After a good many hours going through the Django code, expecting there to be a problem with file handles becoming invalidated or the read position not being reset to the beginning of the file, I finally decided to look at PIL, the Python Imaging Library. It turns out that at this point, due to some weirdness with unit tests, PIL hadn’t populated its known list of file formats. All it knew was BMP, and so my perfectly fine PNG file didn’t work.
The solution? Be sure to import PIL and call init() before the unit tests begin. If you have a custom runner (as we do), then putting it in here is appropriate. Just add the following:
from PIL import Image Image.init()
Hopefully this helps someone else with the problems I’ve dealt with the past few days.
Thanks for the tips re: testing an ImageField. I found this by googling: ‘django “client.post” imagefield’ and it’s exactly what I was looking for 🙂