Как делать mock изображений (avatar + thumbnail) для тестов в Django

Задача состоит в следующем: необходимо при сохранении записи в БД генерировать thumbnail с определенным названием и определенного размера. При ручном тестировании всё работает как нужно, но при написании тестов возникают некоторые трудности.

Для понимания происходящего есть следующий код

Файл models.py

class Reporter(models.Model):
    THUMB_SIZE = (84, 84)

    avatar = models.ImageField(max_length=200, blank=True, null=True)
    thumbnail = models.ImageField(max_length=200, blank=True, null=True)
    ...

    def save(self, *args, kwargs):
        self.generate_thumbnail()
        super().save(*args, kwargs)

    def generate_thumbnail(self):
        if self.avatar:
            with Image.open(self.avatar.path) as image_file:
                cropped_image = crop_square(image_file)  # Обрезка до квадрата
                cropped_image.thumbnail(Reporter.THUMB_SIZE, Image.ANTIALIAS)

                bytes_stream = io.BytesIO()
                cropped_image.save(bytes_stream, cropped_image.format)

                content_file = ContentFile(bytes_stream.getvalue())
                file_path = reporter_thumbnail_path(self, self.avatar.path)  # Генерация пути и имени файла
                self.thumbnail.save(name=file_path, content=content_file, save=False)

Файл с тестом test_models.py


def mock_image_open(*args, **kwargs):
    thumb = Image.new('RGB', size=(120, 100))

    thumb_io = io.BytesIO()
    thumb.save(fp=thumb_io, format='JPEG')

    return ContentFile(thumb_io.getvalue())


class TestModels(unittest.TestCase):
    ...  # Некоторые данные для тестов

    @patch('builtins.open', mock_image_open)
    def test_generate_thumbnail(self):
        reporter = ReporterFactory()  # Используется factory boy; avatar генерируется здесь же

        thumbnail_dimensions = reporter.thumbnail.width, reporter.thumbnail.height
        self.assertEqual(Reporter.THUMB_SIZE, thumbnail_dimensions)  # Возникает ошибка, т.к. в thumbnail_dimensions хранится кортеж (120, 100) изображения, которое создалось в mock_image_open

Как писал ранее, при ручном тестировании thumbnail создается верный, но в тестах изображение в конечном итоге никак не изменяется.

Пробую дебажить проходя по каждой строчке метода generate_thumbnail. В моменте вызова контекстного менеджера вызывается mock-функция (mock_image_open) которая возвращает файл, затем этот файл обрезается до квадрата и уменьшается до размера THUMB_SIZE. При этом после выполнения инструкции self.thumbnail.save(name=file_path ...) смотрю значение self.thumbnail - там размер указан 84х84, но как только происходит выход из метода generate_thumbnail (в переопределенный метод save()), то thumbnail сохраняется с размерами 120х100.

Я не понимаю из-за чего такое происходит. Помогите, пожалуйста, разобраться. Если есть другое решение или способ правильно это протестить, то буду рад ознакомиться с ним.

Вернуться на верх