Pytest patch继承Django模型的字段default属性失效问题咨询
问题原因
- Python 的
mock遵循「在哪里使用,就在哪里 patch」的规则,你当前的写法 mock 的是 uuid 模块根路径下的uuid4函数,但实际被 BaseModel 使用的uuid4已经在模块导入阶段就被加载到了common.models的命名空间中:
你在common/models.py顶部执行from uuid import uuid4时,就已经把 uuid 模块里的uuid4函数引用复制到了common.models作用域下,BaseModel中guid字段的default参数绑定的是这个复制后的引用,而非原 uuid 模块的uuid4。你直接 patchuuid.uuid4只会修改原模块的引用,不会影响已经被导入到common.models里的函数,所以创建模型实例时调用的还是原始的uuid4,mock 自然不会被触发。 - 额外的小问题:你的测试代码里 mock 返回的是字符串,但 Django 的
UUIDField存储的是 UUID 类型对象,即使 mock 生效,直接用字符串和entity.guid做相等判断也会失败。
解决方案
两种可选方案,优先选第一种,不需要修改生产代码:
方案1:patch 实际使用位置的 uuid4
把 mock 的路径改成 common.models.uuid4,也就是 uuid4 实际被调用的作用域路径,同时调整返回值为 UUID 类型即可:
import uuid def test_model_create(mocker): # Given test_guid = uuid.UUID("3fa85f64-5717-4562-b3fc-2c963f66afa6") mock_guid = mocker.patch("common.models.uuid4", return_value=test_guid) # When entity = Entity.objects.create(name="test_name") # Then mock_guid.assert_called_once() assert test_guid == entity.guid
方案2:修改字段 default 为延迟导入路径
如果不想调整测试的 patch 路径,也可以修改生产代码中 guid 字段的 default 写法,用字符串形式的导入路径让 Django 延迟解析函数:
# common/models.py 中修改字段定义 guid = models.UUIDField(unique=True, default="uuid.uuid4", editable=False)
这种写法下你原来的 patch 写法可以生效,但需要修改生产逻辑,优先级低于方案1。
内容的提问来源于stack exchange,提问作者Khamidulla
相关产品推荐
相关产品推荐

