
在 pytest 中,直接为 Mock 对象赋值 __call__ 属性无法生效,因为 Mock 类对 __call__ 有特殊处理;正确方式是直接将返回值传给 Mock() 构造函数,使其自身可调用并返回预期结果。
在 pytest 中,直接为 mock 对象赋值 `__call__` 属性无法生效,因为 `mock` 类对 `__call__` 有特殊处理;正确方式是直接将返回值传给 `mock()` 构造函数,使其自身可调用并返回预期结果。
在单元测试中,我们常需要模拟一个“可调用对象”(callable),例如函数、类实例(实现了 __call__)或装饰器。当你尝试通过 my_mock.__call__ = Mock(return_value=...) 的方式手动设置 __call__ 方法时,会发现 my_mock() 仍返回一个新的 Mock 实例,而非你期望的值——这是因为 Mock 类内部将 __call__ 视为一个内置行为控制属性,而非普通属性:它会忽略你对 __call__ 的显式赋值,转而使用其自身的调用逻辑。
✅ 正确做法是:直接利用 Mock 构造函数的 return_value 参数。Mock 实例默认就是可调用的,且其 __call__ 行为由 return_value(或 side_effect)统一控制:
from unittest.mock import Mock # 推荐使用 unittest.mock(pytest 内部也基于此) # from pytest import Mock # 不推荐:pytest 本身不提供 Mock,实际是导入自 unittest.mock mock_output = "mock" my_mock = Mock(return_value=mock_output) # 验证两种调用方式效果一致 assert my_mock.__call__() == "mock" # ✅ assert my_mock() == "mock" # ✅
⚠️ 注意事项:
- 不要混用 unittest.mock.Mock 和非标准别名(如 from pytest import Mock 是错误认知;pytest 不导出 Mock,该写法通常因隐式导入或误配环境导致,应显式使用 from unittest.mock import Mock);
- 若需模拟多次调用返回不同值,使用 side_effect:
my_mock = Mock(side_effect=["first", "second", ValueError("boom")]) assert my_mock() == "first" assert my_mock() == "second" try: my_mock() except ValueError as e: assert str(e) == "boom" - 若需验证 __call__ 是否被调用及参数,可结合 assert_called_once_with():
my_mock(42, key="val") my_mock.assert_called_once_with(42, key="val")
总结:Mock(return_value=x) 创建的对象天然支持 obj() 和 obj.__call__() 两种调用语法,且行为完全一致;手动覆盖 __call__ 属性是无效的惯性误区。掌握这一机制,能写出更简洁、可靠、符合 Python Mock 设计意图的测试代码。

















