如何在单元测试中Mock Pydantic验证器?调用断言失败排查
解决Pydantic验证器Mock路径错误的问题
核心问题在于你Mock的是验证器的原定义模块,而非模型实际调用的模块内引用。Pydantic在绑定验证器时,会使用模型模块中导入的函数引用,而非直接调用原validators模块里的函数,所以必须修正Patch路径。
典型项目结构(按你描述的场景)
your_project/ ├── awx_models.py # 存放Pydantic模型 ├── validators.py # 抽离的通用验证器函数 └── tests/ └── test_awx_models.py # 单元测试文件
示例代码与错误原因
awx_models.py(模型文件)
from pydantic import BaseModel, validator from validators import validate_hostname, validate_ip_format class AWXHost(BaseModel): hostname: str ip: str _validate_host = validator('hostname', allow_reuse=True)(validate_hostname) _validate_ip = validator('ip', allow_reuse=True)(validate_ip_format)
错误的测试代码(Patch路径错误)
from unittest.mock import patch from awx_models import AWXHost def test_validators_called(): # 错误:Patch了原validators模块的函数,而非模型模块内的引用 with patch('validators.validate_hostname') as mock_host, \ patch('validators.validate_ip_format') as mock_ip: mock_host.return_value = "valid-host" mock_ip.return_value = "192.168.1.1" AWXHost(hostname="abc", ip="192.168.1.1") # 断言失败:验证器未被检测到调用 mock_host.assert_called_once()
修正后的测试代码
需要Patch模型模块中导入的验证器引用,也就是awx_models.validate_hostname而非validators.validate_hostname:
from unittest.mock import patch from awx_models import AWXHost def test_validators_called(): # 正确:Patch模型模块内的验证器引用 with patch('awx_models.validate_hostname') as mock_host, \ patch('awx_models.validate_ip_format') as mock_ip: mock_host.return_value = "valid-host" mock_ip.return_value = "192.168.1.1" AWXHost(hostname="abc", ip="192.168.1.1") # 不仅能断言调用次数,还能检查传入的参数 mock_host.assert_called_once_with("abc") mock_ip.assert_called_once_with("192.168.1.1")
如果测试文件在tests目录下,需要使用完整的项目包路径(假设项目包名为your_project):
with patch('your_project.awx_models.validate_hostname') as mock_host: # ... 测试逻辑
关键原理
当你在awx_models.py中执行from validators import validate_hostname时,会在awx_models模块内创建一个指向原函数的引用。Pydantic的validator装饰器绑定的是这个模块内的引用,而非原validators模块中的函数。因此,只有Patch这个模块内的引用,才能拦截模型初始化时的验证器调用。
批量Mock的小技巧
如果需要Mock多个验证器,可以直接Patch整个validators模块在模型中的导入引用:
with patch('awx_models.validators') as mock_validators: # 配置各个验证器的返回值 mock_validators.validate_hostname.return_value = "valid-host" mock_validators.validate_ip_format.return_value = "192.168.1.1" AWXHost(hostname="abc", ip="192.168.1.1") # 断言各个验证器被调用 mock_validators.validate_hostname.assert_called_once() mock_validators.validate_ip_format.assert_called_once()
内容的提问来源于stack exchange,提问作者Heetola
相关产品推荐
相关产品推荐

