单元测试因Tenacity装饰器失败,如何Patch该装饰器?
问题分析与解决
问题根源
你的单元测试失败有两个核心原因:
- Tenacity装饰器默认行为:
@retry装饰器默认会把实例方法转换为普通函数,导致调用时不会自动传入self参数,mock捕获到的调用仅包含offset=0,但你的断言错误地添加了额外参数。 - 断言参数错误:即使没有装饰器,你写的
mock_get_systems_chunk.assert_called_once_with(mock_ax_service._get_systems_chunk, offset=0)也是错误的——实例方法的mock调用第一个参数应该是实例本身(mock_ax_service),而非实例的方法对象。
解决方案
方案1:修正测试断言(无需修改业务代码)
直接调整断言,匹配Tenacity装饰后方法的调用参数:
# 替换原有的断言行 mock_get_systems_chunk.assert_called_once_with(offset=0)
方案2:修改Tenacity装饰器,保留实例方法绑定(更规范的写法)
给@retry添加method=True参数,让装饰器正确处理实例方法,保留self自动传入的特性:
@retry( stop=stop_after_attempt(5), wait=wait_exponential(multiplier=8, min=5, max=120), method=True # 新增此参数,确保实例方法绑定特性 ) def _get_systems_chunk(self, offset: int) -> dict: # 原有业务代码不变
同时修正测试断言的第一个参数为实例对象:
# 替换原有的断言行 mock_get_systems_chunk.assert_called_once_with(mock_ax_service, offset=0)
验证
两种方案都能解决测试失败问题:
- 方案1快速适配现有装饰器行为,无需改动业务代码;
- 方案2更符合Python实例方法的规范,避免后续其他测试或调用出现类似问题。
内容的提问来源于stack exchange,提问作者PandasM
相关产品推荐
相关产品推荐

