Django mocking storage on model with update() throws error

巧了我就是萌 提交于 2019-12-12 12:57:41

问题


I have a small project and I'm working on some tests. Recently I asked a question: django-test-mocked-imagefield-prevent-upload-or-clean-after-test. I've made some progress in mocking the storage, but currently I'm running into an issue with mocking storage on a model with an update() in the save() method.

Current situation:

<..crop..>
import mock

current_storage = 'django.core.files.storage.default_storage._wrapped'
def _mock_storage():
    return mock.MagicMock(spec=Storage, name="StorageMock")

class ProjectsTest(TestCase):
    fixtures = ['projects']

    @mock.patch(current_storage, _mock_storage())
    def _create_project(self, name):
    return Project.objects.create(
            name=name,
            short_description="Short description A",
            full_description="Full description A",
            url="http://test-project-url.com/",
            is_published=True)

    @mock.patch(current_storage, _mock_storage())
    def _create_project_image(self, project, name):
    return ProjectImage.objects.create(
            project=project,
            name=name,
            description="Description",
            image=self._create_mock_image(name="Mocked Image"),
            is_primary=True,
            is_published=True)

Creating a new object with _create_project() works fine. Creating a new object in _create_project_image() throws me an error (stacktrace on the bottom of post):

ValueError: Failed to insert expression "<MagicMock name='StorageMock.save().width.resolve_expression()' id='140674024419280'>" on projects.ProjectImage.image_width. F() expressions can only be used to update, not to insert.

This is because I have an update() in the save of the model (some fields are removed since they are not interesting to the question):

class ProjectImage(models.Model):
    project = models.ForeignKey(
        'projects.Project')
    name = models.CharField(
        _("Image name"),
        max_length=35)
    image = models.ImageField(
        _("Project image"),
        upload_to=project_image_upload_location,
        width_field='image_width',
        height_field='image_height')
    image_width = models.IntegerField(
        default=0)
    image_height = models.IntegerField(
        default=0)
    is_primary = models.BooleanField(
        _("Primary project image?"),
        default=False)

    def save(self, *args, **kwargs):
        self.update_primary_project_image()
        return super(ProjectImage, self).save(*args, **kwargs)

    def update_primary_project_image(self):
        if self.is_primary:
            self.__class__.objects \
                .filter(project=self.project, is_primary=True) \
                .update(is_primary=False)

stacktrace:

Creating test database for alias 'default'...
.......E.
======================================================================
ERROR: test_unset_current_primary_image_on_save (projects.tests.ProjectsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/edwin/git/portofolio/apps/projects/tests.py", line 105, in test_unset_current_primary_image_on_save
    self._create_project_image(project=project, name="Image A2")
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/home/edwin/git/portofolio/apps/projects/tests.py", line 42, in _create_project_image
    is_published=True)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/query.py", line 399, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/edwin/git/portofolio/apps/projects/models.py", line 91, in save
    return super(ProjectImage, self).save(*args, **kwargs)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/base.py", line 796, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/base.py", line 824, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/base.py", line 908, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/base.py", line 947, in _do_insert
    using=using, raw=raw)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/query.py", line 1045, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1053, in execute_sql
    for sql, params in self.as_sql():
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1006, in as_sql
    for obj in self.query.objs
  File "/home/edwin/.virtualenvs/portofolio/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 940, in prepare_value
    'can only be used to update, not to insert.' % (value, field)
ValueError: Failed to insert expression "<MagicMock name='StorageMock.save().width.resolve_expression()' id='139904200277904'>" on projects.ProjectImage.image_width. F() expressions can only be used to update, not to insert.

----------------------------------------------------------------------
Ran 9 tests in 0.123s

question: How can I properly test an update in a model with a mocked storage? Or am trying to do something here that is totally impossible?

Any suggestions, explanations or a pushes in the right direction to solve this issue will be appreciated. Thank you.

来源:https://stackoverflow.com/questions/42316729/django-mocking-storage-on-model-with-update-throws-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!