测试Django Model.clean()时unittest.mock patch报F()表达式错误求助
问题描述
在Django开发中,我通过Model.clean()方法验证用户提交的表单,验证过程会根据HTTP请求响应更新部分字段。想用Python的unittest模拟HTTP请求测试Model.clean()方法,但运行测试时出错。
相关代码
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.
修复方案
问题出在测试代码对Mock对象的赋值方式错误。直接把mock_get_version赋值为字符串"5678",并没有改变被patch方法的返回值,原MagicMock对象仍在生效,导致Django将其识别为数据库表达式,从而报错。
正确做法是通过return_value属性设置Mock方法的返回值,修改测试方法如下:
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")
设置后,GitHosting.get_version()被调用时会返回指定字符串"5678",而非MagicMock对象,Django就能正确处理该值并插入数据库。
内容的提问来源于stack exchange,提问作者Raniere Silva
相关产品推荐
相关产品推荐

