使用unittest.mock.patch模拟类的__call__方法

问题描述 投票:0回答:1

我有一个类(ClassToBeMocked),它在另一个类(ContainerClass)的init中实例化。 我想模拟实例化的 ClassToBeMocked 并替换其 dunder call 方法。

我的代码适用于常规方法,但不适用于 call dunder 方法。

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
python mocking callable-object
1个回答
0
投票

在下面的示例中,

instance_cls()
不会调用
instance_cls.__call__
。它调用
type(instance_cls).__call__(instance_cls)
,因为 python 实际上调用类上定义的
__call__
方法,而不是实例(有关更多信息,请检查堆栈溢出上的 answer

>>> class ClassToBeMocked:
...     def __call__(self):
...         return 42
...
>>> instance_cls = ClassToBeMocked()
>>> instance_cls() 
... 42

关于您的示例,只需将

instance.__call__ = MagicMock(return_value="Hey")
更改为
instance.__class__.__call__ = MagicMock(return_value="Hey")
就可以了。

完整代码如下:

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.__class__.__call__ = MagicMock(return_value="Hey")
    instance.regular_method = MagicMock(return_value="Hey")
    
    test = ContainerClass()
    print(test.run_a())  # print "Hey"
    print(test.run_b())  # print "Hey"
© www.soinside.com 2019 - 2024. All rights reserved.