Python unittest mock报AttributeError找不到extract属性排查
报错根因
两个版本代码报错核心来自三个问题:
- 初始版本mock目标错误:
extract是DataExtractor类的实例方法,不属于Task类,对workflow.workflow.Task.extract打补丁必然触发属性不存在的错误。 - 测试目标偏离:你要验证的是
Task.extract_data的逻辑,更新后的测试代码直接实例化DataExtractor调用extract,完全没有覆盖Task类的业务逻辑。 - 业务代码存在语法错误:更新后的
workflow.py中extract_data方法里key=key引用了未定义的变量,运行会直接抛出NameError;初始版本直接用类调用实例方法Task.extract_data()也会因缺少self参数报错。
正确mock实现方案
Python mock的核心规则是在哪用,在哪patch:你在workflow.workflow模块中导入并使用了DataExtractor,直接patch这个模块下的DataExtractor引用即可。
第一步:修复业务代码语法问题
先修正workflow.py的未定义变量问题,调整后代码如下:
# src/workflow/workflow.py from data_extractor.data_extractor import DataExtractor class Task: def __init__(self, task_type: str, name: str, key: str) -> None: self.name = name self.task_type = task_type self.key = key self.extractor = DataExtractor() def extract_data(self): # key从实例属性获取,避免未定义错误 obj = self.extractor.extract(name=self.name, key=self.key) return obj
第二步:编写正确的单元测试
测试逻辑围绕Task.extract_data展开,验证方法调用时底层依赖的行为符合预期,调整后测试代码如下:
# tests/test_extract.py import unittest from unittest import mock from workflow.workflow import Task class TestTaskExtract(unittest.TestCase): @mock.patch("workflow.workflow.DataExtractor") def test_extract_from_snowflake(self, mock_data_extractor): # 配置mock返回值:模拟extractor.extract的返回结果 mock_extractor_instance = mock_data_extractor.return_value mock_extractor_instance.extract.return_value = [{"id": 1, "value": "test"}] # 实例化Task,调用待测试的目标方法 test_task = Task(task_type="snowflake", name="entities", key="11") actual_result = test_task.extract_data() # 校验返回值符合预期 self.assertEqual(actual_result, [{"id": 1, "value": "test"}]) # 校验DataExtractor被正确实例化 mock_data_extractor.assert_called_once_with() # 校验extract方法被传入正确参数调用 mock_extractor_instance.extract.assert_called_once_with(name="entities", key="11") if __name__ == "__main__": unittest.main()
常见mock踩坑提醒
- 实例方法必须通过类实例调用:直接写
Task.extract_data()属于错误用法,会因为缺少绑定的self参数抛出异常。 - 不要乱改patch路径:不需要patch
data_extractor.data_extractor.DataExtractor,因为workflow模块已经把DataExtractor导入到自身命名空间,你要替换的是workflow模块下的这个引用。 - 断言要匹配正确的mock对象:装饰器注入的
mock_data_extractor对应DataExtractor类本身,用来校验实例化逻辑;mock_data_extractor.return_value对应实例化后的extractor对象,它的extract方法才是需要校验入参的目标。
内容的提问来源于stack exchange,提问作者user6308605
相关产品推荐
相关产品推荐

