Какой лучший способ издеваться над пользователем Django? - PullRequest
3 голосов
/ 06 октября 2019

Я пытаюсь создать экземпляр User через Mock. Этот фиктивный экземпляр передается другой модели Профиль , где я проверяю наличие ошибок проверки при вызове метода очистки.

Однако я получаю: AttributeError: Mock object has no attribute '_state'

Это предыдущий пост: Как высмеивать пользователей и запросы в django . Тем не менее, я хочу избегать любых вызовов базы данных.

Что можно сделать по-другому, чтобы в этом случае было издеваться?

#models.py

class Profile(models.Model):

    hobby = "Hobbyist"
    develop = "Developer"
    coding_level = (
        (hobby, hobby),
        (develop, develop)
    )

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    birth = models.DateField(verbose_name="Date Of Birth")
    coding_level = models.CharField(
        verbose_name="Experience",
        max_length=20,
        choices=coding_level, default=hobby, blank=False
    )
    bio = models.TextField(
        verbose_name="User Bio",
        validators=[MinValueValidator(10)]
    )
    github = models.URLField(
        verbose_name="GitHub link",
        validators=[check_submitted_link],
        unique=True
    )
    avatar = models.ImageField(upload_to="images/%Y/%m/%d/")
#test_models.py

class TestProfile__001(SimpleTestCase):

    def setUp(self):
        self.test_user = Mock(
            spec=User,
            username="test_username",
            email="test@email.com"
        )

        self.profile_data = {
            'user': self.test_user,
            'birth': '2019-10-07',
            'coding_level': 'hobbyist',
            'bio': "",
            'github': "http://www.test.com",
            'avatar': "image.txt"
        }

    def test_create_profile_fail(self):
        with self.assertRaises(ValidationError):
            test_profile = Profile(**self.profile_data)
            test_profile.clean_fields()

1 Ответ

0 голосов
/ 06 октября 2019

Я бы сказал, что нет смысла тестировать clean_fields, поскольку уже является частью очень хорошо протестированной кодовой базы Django. Но если вы настаиваете на его тестировании, вам определенно не стоит издеваться над User.

Давайте посмотрим на код, который вы пытаетесь проверить здесь (это отрывок из clean_fields ):

        raw_value = getattr(self, f.attname)
        if f.blank and raw_value in f.empty_values:
            continue
        try:
            setattr(self, f.attname, f.clean(raw_value, self))
        except ValidationError as e:
            errors[f.name] = e.error_list

Мы видим, что он проходит через каждое поле вмодель, пытающаяся вызвать свой метод clean ( source ):

def clean(self, value):
    """
    Validate the given value and return its "cleaned" value as an
    appropriate Python object. Raise ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value) 
    return value

OneToOneField сама не вводит ни один из этих методов, это делается выше в иерархии классов, вForeignKey класс. И вот основная часть метода validate:

    using = router.db_for_read(self.remote_field.model, instance=model_instance)
    qs = self.remote_field.model._default_manager.using(using).filter(
        **{self.remote_field.field_name: value}
    )
    qs = qs.complex_filter(self.get_limit_choices_to())
    if not qs.exists():
        raise exceptions.ValidationError(
            self.error_messages['invalid'],
            code='invalid',
            params={
                'model': self.remote_field.model._meta.verbose_name, 'pk': value,
                'field': self.remote_field.field_name, 'value': value,
            },  # 'pk' is included for backwards compatibility
        )

Как видите, вся проверка состоит только из конструкции запроса с вызовом базы данных! Поэтому, если вы пытаетесь избежать попадания в базу данных, вам следует просто полностью пропустить проверку любых внешних ключей:

def test_create_profile_fail(self):
    with self.assertRaises(ValidationError):
        test_profile = Profile(**self.profile_data)
        test_profile.clean_fields(exclude=['user'])  # don't forget to explain your decision in the comments

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...