如何用unittest.mock.patch模拟类的__call__方法?
如何Mock类实例的__call__特殊方法
我需要Mock在ContainerClass的__init__方法中实例化的ClassToBeMocked对象,替换它的__call__特殊方法。目前代码对普通方法有效,但__call__方法不生效,具体代码、当前输出和期望输出如下:
代码示例
from unittest.mock import patch, Mock, MagicMock class ClassToBeMocked: def __call__(self, x): return 42 def regular_method(self, x): return 42 class ContainerClass: def __init__(self): self.runner = ClassToBeMocked() def run_a(self): return self.runner(x="x") def run_b(self): return self.runner.regular_method(x="x") with patch("__main__.ClassToBeMocked") as mock: instance = mock.return_value instance.__call__ = MagicMock(return_value="Hey") instance.regular_method = MagicMock(return_value="Hey") test = ContainerClass() print(test.run_a()) print(test.run_b())
当前输出
<MagicMock name='ClassToBeMocked()()' id='140033866116784'> Hey
期望输出
Hey Hey
问题原因
MagicMock的特殊方法(如__call__)无法通过直接赋值新的MagicMock对象来覆盖,因为MagicMock会动态生成这些特殊方法的代理逻辑,直接赋值的对象不会被实际调用时使用。
解决方法
有两种简单的修改方式可以实现需求:
方式一:设置mock实例的return_value
调用mock实例本身等价于调用它的__call__方法,因此直接设置实例的return_value即可:
with patch("__main__.ClassToBeMocked") as mock: instance = mock.return_value # 替换原有的instance.__call__赋值语句 instance.return_value = "Hey" instance.regular_method = MagicMock(return_value="Hey") test = ContainerClass() print(test.run_a()) # 输出 Hey print(test.run_b()) # 输出 Hey
方式二:设置__call__方法的return_value
不重新赋值__call__,而是直接修改原有__call__方法的返回值:
with patch("__main__.ClassToBeMocked") as mock: instance = mock.return_value # 替换原有的instance.__call__赋值语句 instance.__call__.return_value = "Hey" instance.regular_method = MagicMock(return_value="Hey") test = ContainerClass() print(test.run_a()) # 输出 Hey print(test.run_b()) # 输出 Hey
处理带参数的场景
如果需要根据传入的参数返回不同结果,可以使用side_effect:
instance.side_effect = lambda x: f"Hey with parameter: {x}"
内容的提问来源于stack exchange,提问作者Hugo Perrier
相关产品推荐
相关产品推荐

