简体   繁体   中英

TypeError: __str__ returned non-string (type MagicMock)

I'm writing some tests for my Django code and I'm mocking file and file storage.

I've found this guide

https://joeray.me/mocking-files-and-file-storage-for-testing-django-models.html

so my mocks look like this

# mocks.py
image_mock = mock.MagicMock(spec=File, name='FileMock')
image_mock.name = 'dummy.jpg'

storage_mock = mock.MagicMock(spec=Storage, name='StorageMock')
storage_mock.url = mock.MagicMock(name='url')
storage_mock.url.return_value = '/tmp/dummy.jpg'

any my failing test looks like this:

import factory
import mock
from imagekit.signals import source_saved
from .mocks import storage_mock, image_mock
from .models import Car


@factory.django.mute_signals(source_saved)
class CarFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Car

    image = image_mock


def test_case_one(self):
    with mock.patch('django.core.files.storage.default_storage._wrapped', storage_mock):
        car = CarFactory.create()

And it fails with the following error:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/base.py:564: in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/django.py:337: in wrapped_generate
    return generate_method(*args, **kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/django.py:141: in _generate
    return super(DjangoModelFactory, cls)._generate(strategy, params)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/base.py:501: in _generate
    return step.build()
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/builder.py:279: in build
    kwargs=kwargs,
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/base.py:315: in instantiate
    return self.factory._create(model, *args, **kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/factory/django.py:185: in _create
    return manager.create(*args, **kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/manager.py:82: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/query.py:422: in create
    obj.save(force_insert=True, using=self.db)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/base.py:741: in save
    force_update=force_update, update_fields=update_fields)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/base.py:779: in save_base
    force_update, using, update_fields,
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/base.py:870: in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/base.py:908: in _do_insert
    using=using, raw=raw)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/manager.py:82: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/query.py:1186: in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1334: in execute_sql
    for sql, params in self.as_sql():
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1278: in as_sql
    for obj in self.query.objs
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1278: in <listcomp>
    for obj in self.query.objs
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1277: in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1218: in prepare_value
    value = field.get_db_prep_save(value, connection=self.connection)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/fields/__init__.py:789: in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
/home/admin/.virtualenvs/car-project/lib/python3.7/site-packages/django/db/models/fields/__init__.py:784: in get_db_prep_value
    value = self.get_prep_value(value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.fields.files.ImageField: image>
value = <[TypeError("__str__ returned non-string (type MagicMock)") raised in repr()] ImageFieldFile object at 0x7f2c94996a58>

    def get_prep_value(self, value):
        value = super().get_prep_value(value)
        # Need to convert File objects provided via a form to string for database insertion
        if value is None:
            return None
>       return str(value)
E       TypeError: __str__ returned non-string (type MagicMock)

I'd appreciate any help with this.


Requirements:

python 3.7

Django==2.2

django-storages==1.7.1

factory-boy==2.12.0

mock==3.0.5

You must also patch ImageField like this

image_name = 'test_image.jpg'
image_field_mock = mock.MagicMock(name='get_db_prep_save')
image_field_mock.return_value = image_name


def test_case_one(self):
    with mock.patch('django.core.files.storage.default_storage._wrapped', storage_mock):
        with mock.patch('django.db.models.ImageField.get_db_prep_save', image_field_mock):
            car = CarFactory.create()

I tried the same guide and ran into the same issue and ultimately I was not able to get it to work. Instead I used: https://github.com/danifus/django-override-storage . That ended up being a much simpler to way to override the file storage when testing in Django.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM