CNK's Blog

Testing File Uploads (in Django)

I am trying to improve the test coverage of our work project and needed to test the avatar upload that is associated with creating users in our project. I didn’t find any place that laid out how to test file uploads. Fortunately the tests for the easy-thumbnails app we use are pretty good and I was able to piece something together using their code as a model.

In case anyone else is looking for something like this, I updated my easy thumbnails example project to include a couple of tests.

    from PIL import Image
    from django.core.files.base import ContentFile
    from django.core.files.uploadedfile import SimpleUploadedFile
    from django.test import TestCase, Client
    from django.core.urlresolvers import reverse
    from django.utils.six import BytesIO
    from .factories import UserFactory
    from .models import UserProfile


    # "borrowed" from easy_thumbnails/tests/test_processors.py
    def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'):
        """
        Generate a test image, returning the filename that it was saved as.

        If ``storage`` is ``None``, the BytesIO containing the image data
        will be passed instead.
        """
        data = BytesIO()
        Image.new(image_mode, size).save(data, image_format)
        data.seek(0)
        if not storage:
            return data
        image_file = ContentFile(data.read())
        return storage.save(filename, image_file)


    class UserTests(TestCase):
        def setUp(self):
            self.user = UserFactory(username='me')

        # deleting the user will remove the user, the user_profile, AND the avatar image
        def tearDown(self):
            self.user.delete()

        def test_adding_an_avatar_image(self):
            # make sure we start out with no UserProfile (and thus no avatar)
            self.assertIsNone(UserProfile.objects.filter(user_id=self.user.id).first())
            myClient = Client()
            myClient.login(username=self.user.username, password='password')

            # set up form data
            avatar = create_image(None, 'avatar.png')
            avatar_file = SimpleUploadedFile('front.png', avatar.getvalue())
            form_data = {'avatar': avatar}

            response = myClient.post(reverse('avatar_form'), form_data, follow=True)
            self.assertRegex(response.redirect_chain[0][0], r'/users/profile/$')
            # And now there is a user profile with an avatar
            self.assertIsNotNone(self.user.profile.avatar)

        def test_uploading_non_image_file_errors(self):
            # make sure we start out with no UserProfile (and thus no avatar)
            self.assertIsNone(UserProfile.objects.filter(user_id=self.user.id).first())
            myClient = Client()
            myClient.login(username=self.user.username, password='password')

            # set up form data
            text_file = SimpleUploadedFile('front.png', b'this is some text - not an image')
            form_data = {'avatar': text_file}

            response = myClient.post(reverse('avatar_form'), form_data, follow=True)
            self.assertFormError(response, 'avatar_form', 'avatar',
                                 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.')