Mocking User File Storage

I created a special backend for storing files that accesses Amazon S3 using boto and stores the files there (I know that django-storage handles this as well, but we ran into several problems with it). I store it in the utils module and use it in my models as follows:

from utils.s3 import S3Storage

class Photo(models.Model):
  image = models.ImageField(storage=S3Storage(), upload_to="images")

Thus, at any time when a photograph with an image file is created, the image file is loaded into the S3 bucket.

I do not want to make calls to S3 during my tests, but figuring out what exactly to mock at this situation is difficult. I can’t mock the entire image field because I need to test model creation through Tastypie.

Any ideas?

+5
source share
2 answers

You can simply make fun of the method _savein the class S3Storageto avoid loading onto S3. You can use instead FileSystemStorage.

My solution for your case would be:

import mock
from utils.s3 import S3Storage
from django.core.files.storage import FileSystemStorage


fss = FileSystemStorage()

@mock.patch.object(S3Storage, '_save', fss._save)
def test_something():
    assert True
+2
source

I tried many other solutions, such as overwrite in settings DEFAULT_FILE_STORAGEor Manh Tai solution. The problem is that Django loads all the models into memory upon initialization, and this makes changing the model attribute a bit unintuitive after setting it.

Tested with Django 2.1 and Python 3:

from unittest.mock import MagicMock
from django.core.files.storage import Storage
from django.core.files.uploadedfile import SimpleUploadedFile

class CreatePhotoTest(TestCase):
    def test_post_photo(self):
        def generate_filename(filename):
            return filename

        def save(name, content, max_length):
            return name

        storage_mock = MagicMock(spec=Storage, name='StorageMock')
        storage_mock.generate_filename = generate_filename
        storage_mock.save = MagicMock(side_effect=save)
        storage_mock.url = MagicMock(name='url')
        storage_mock.url.return_value = 'http://example.com/generated_filename.png'

        Photo._meta.get_field('image').storage = storage_mock

        img = SimpleUploadedFile('file.png', b"file_content", content_type="image/png")
        data = {
            'signed_contract': img
        }
        response = self.client.post('/endpoint', data, format='multipart')

        self.assertTrue(storage_mock.save.called)
        generated_filename = storage_mock.save.call_args_list[0][0][0]
        uploaded_file = storage_mock.save.call_args_list[0][0][1]
        self.assertEqual(uploaded_file.name, 'file.pdf')

I created generate_filename()and save(), but you do not need to do this if you do not want. This was done in order to emulate the behavior of the real repository as much as possible and test it in the test.

0
source

Source: https://habr.com/ru/post/1533977/


All Articles