Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to mock file uploads while testing views

I want to unit test my view. The view is supposed to get images from the form, upload them to Amazon S3 and finally show previews of the uploaded images.

I'd like to ask anybody for a complete example of:

  1. How to write a unit test for the view.
  2. How and what to mock in the test in order to keep testing speed high.
like image 860
Dmitry Wojciechowski Avatar asked Sep 07 '13 03:09

Dmitry Wojciechowski


2 Answers

The view could be tested using RequestFactory. That way you skip all the middleware and url resolution that slows your tests down. Note that you'll have to modify the returned request object so that all decorators decorating your view function are fine with it.

When testing you could provide a dummy storage for tests so that S3 wouldn't be hit, and provide a 1x1 image file so that PIL won't scream it doesn't look like image file (the file could be reused in your other test cases, instead of being programatically created). Or, depending on used client library, mock the save() or _save() methods of the library of choice's storage object at the point you are doing the actual mocking (perhaps myapp.models if using the storage kwarg of the ImageField, or django internals if using the settings).

from django.test.client import RequestFactory
from django.test import TestCase

from myapp import views


class MyViewTest(TestCase):
    def setUp(self):
        self.rq = RequestFactory()

    def test_view(self):
        with open('test_data/test_img.png', 'rb') as img:
            req = self.rq.post('my_view_url', {'my_post': 'data', 'test': 1, 'image': img})
            resp = views.my_view(req)
            # ... asserts ...
like image 126
Maciej Gol Avatar answered Oct 01 '22 20:10

Maciej Gol


I am not sure you can use this in your context but SimpleUploadedFile helped me test an upload view without touching the db or file system.

As you can see bellow I have a hardcoded image in code which I use to initialize the SimpleUploadedFile object. This way the SimpleUploadedFile really behaves like an image since it has a valid binary content and a valid filename.

# hex encoded bytes of a tiny valid png file
valid_png_hex = ['\x89', 'P', 'N', 'G', '\r', '\n', '\x1a', '\n', '\x00',
                 '\x00', '\x00', '\r', 'I', 'H', 'D', 'R', '\x00',
                 '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01',
                 '\x08', '\x02', '\x00', '\x00', '\x00', '\x90',
                 'w', 'S', '\xde', '\x00', '\x00', '\x00', '\x06', 'b', 'K',
                 'G', 'D', '\x00', '\x00', '\x00', '\x00',
                 '\x00', '\x00', '\xf9', 'C', '\xbb', '\x7f', '\x00', '\x00',
                 '\x00', '\t', 'p', 'H', 'Y', 's', '\x00',
                 '\x00', '\x0e', '\xc3', '\x00', '\x00', '\x0e', '\xc3',
                 '\x01', '\xc7', 'o', '\xa8', 'd', '\x00', '\x00',
                 '\x00', '\x07', 't', 'I', 'M', 'E', '\x07', '\xe0', '\x05',
                 '\r', '\x08', '%', '/', '\xad', '+', 'Z',
                 '\x89', '\x00', '\x00', '\x00', '\x0c', 'I', 'D', 'A', 'T',
                 '\x08', '\xd7', 'c', '\xf8', '\xff', '\xff',
                 '?', '\x00', '\x05', '\xfe', '\x02', '\xfe', '\xdc', '\xcc',
                 'Y', '\xe7', '\x00', '\x00', '\x00', '\x00',
                 'I', 'E', 'N', 'D', '\xae', 'B', '`', '\x82']
valid_png_bin = "".join(valid_png_hex)
png = SimpleUploadedFile("tiny.png", valid_png_bin)
post_data = {u'image': [png], ...}
like image 39
dsalaj Avatar answered Oct 01 '22 20:10

dsalaj