Python unittest.mock patch fail с выражениями F() можно использовать только для обновления, но не для вставки
Минимальный рабочий пример доступен по адресу https://github.com/rgaiacs/django-mwe-magicmock.
При работе с Django я использую Model.clean()
для проверки формы, отправленной пользователем. Во время проверки некоторые поля могут быть обновлены на основе ответа HTTP-запроса. Я хочу протестировать Model.clean()
, используя unittest
Python и имитируя HTTP-запрос.
Мой app/models.py
- это
import logging
from django.core.exceptions import ValidationError
from django.db import models
from .aid import GitHosting
logger = logging.getLogger(__name__)
class Resource(models.Model):
code_repository = models.URLField(
help_text="Link to the repository where the un-compiled, human readable code and related code is located."
)
version = models.CharField(
blank=True,
# Git hash contains 40 characters
max_length=50,
default="HEAD",
help_text="The version of the resource in the format of a Git commit ID or Git tag.",
)
def clean(self):
git_host = GitHosting()
self.version = git_host.get_version()
и мой app/tests.py
это
import logging
from unittest.mock import patch
from django.test import TestCase
from django.urls import reverse
from .models import Resource
logger = logging.getLogger(__name__)
@patch("app.models.GitHosting.get_version")
class ResourceViewTestCase(TestCase):
def test_add_resource(self, mock_get_version):
mock_get_version = "5678"
logger.error("Submitting form ...")
response = self.client.post(reverse("app:index"), {
"code_repository": "http://mygit.com/foo/bar"
})
resource = Resource.objects.get(id=1)
self.assertEqual(resource.version, "5678")
Когда я запускаю python manage.py test
, тест завершается с ошибкой
ValueError: Failed to insert expression "<MagicMock name='get_version().resolve_expression()' id='139668720464128'>" on app.Resource.version. F() expressions can only be used to update, not to insert.
Как я могу исправить свой тест? Спасибо!
Спасибо STerliakov за ответ в комментариях. Ошибка была исправлена предоставлением атрибута return_value
. Полный фрагмент кода выглядит так
import logging
from unittest.mock import patch
from django.test import TestCase
from django.urls import reverse
from .models import Resource
logger = logging.getLogger(__name__)
@patch("app.models.GitHosting.get_version")
class ResourceViewTestCase(TestCase):
def test_add_resource(self, mock_get_version):
mock_get_version.return_value = "5678"
logger.error("Submitting form ...")
response = self.client.post(reverse("app:index"), {
"code_repository": "http://mygit.com/foo/bar"
})
resource = Resource.objects.get(id=1)
self.assertEqual(resource.version, "5678")