factoryboy не переопределяет свойства модели django

Я пытаюсь переопределить пользовательское свойство модели Django через factory_boy для целей тестирования. Но похоже, что он просто использует поведение модели по умолчанию. Фабричный мальчик не может изменить поведение пользовательских атрибутов по умолчанию?

Вот базовый тест, который я написал:

models.py:

class Session(models.Model):
    name = models.CharField(max_length=100)

    @property
    def foo(self):
        return method_not_callable_in_testing()

def method_not_callable_in_testing():
    return 42

SessionFactory.py:

class SessionFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Session

    name = "session"
    foo = 1337

tests.py: класс TestSession(TestCase):

def test_custom_attribute_overwritten_by_factoryboy(self):
    session = SessionFactory.create()
    self.assertEquals(session.foo, 1337)

При запуске тестов я получаю следующую ошибку:

F
======================================================================
FAIL: test_custom_attribute_overwritten_by_factoryboy (bar.tests.TestSession)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/sh4ke/repos/foo/bar/tests.py", line 10, in test_custom_attribute_overwritten_by_factoryboy
    self.assertEquals(session.foo, 1337)
AssertionError: 42 != 1337

person Sh4kE    schedule 20.05.2016    source источник


Ответы (1)


tl;dr

factory_boy может изменять «настраиваемые атрибуты» (я полагаю, вы имеете в виду те, которые не django Fields), но он не может изменять атрибуты только для чтения, что вы и пытаетесь сделать.

Больше информации

Ваша проблема в том, что вы пытаетесь использовать фабрику для установки атрибута свойства, доступного только для чтения. Грубо говоря, комбинация factory_boy и django означает, что вызов SessionFactory() выполняется:

session = Session()
session.foo = 1337

Но я бы не ожидал, что это сработает, потому что, если вы не объявите метод @foo.setter, @property предполагает, что вам нужно свойство только для чтения, и поэтому вызывает ошибку атрибута при попытке установить его.

Странно то, что вы не видите эту ошибку, и оказывается, что django незаметно ее подавляет! Он видит, что ваша модель имеет атрибут foo, выполнив getattr(session, 'foo'), но он обернул все это, включая setattr, внутри try: except AttributeError:, поэтому, хотя он обнаруживает и инициирует попытку установить атрибут, который не существует вообще, он также ловит и спокойно игнорирует неудачный случай попытки установить свойство только для чтения.

Я подозреваю, что это ошибка ... поэтому, вероятно, попытаюсь поднять ее с сообществом django.

person daphtdazz    schedule 20.05.2016
comment
Я ответил на вопрос буквально, но если вам действительно нужен способ имитировать методы при тестировании, вам следует использовать модуль mock (unittest.mock в python 3) и функцию patch, которые должны помочь вам сделать то, что вы хотеть. - person daphtdazz; 20.05.2016