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