I have a class (ClassToBeMocked) that is instantiated in the init of another class (ContainerClass). I would like to mock the instantiated ClassToBeMocked and replace its dunder call method.
My code works for regular methods but not for the call dunder method.
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())
This outputs :
<MagicMock name='ClassToBeMocked()()' id='140033866116784'>
Hey
While I want to have
Hey
Hey
In the example below, instance_cls()
does not call instance_cls.__call__
. It calls type(instance_cls).__call__(instance_cls)
as python actually calls the __call__
method defined on the class, not the instance (for more information check this answer on stack overflow).
>>> class ClassToBeMocked:
... def __call__(self):
... return 42
...
>>> instance_cls = ClassToBeMocked()
>>> instance_cls()
... 42
Regarding you example, just change instance.__call__ = MagicMock(return_value="Hey")
to instance.__class__.__call__ = MagicMock(return_value="Hey")
and it should work.
Full code below :
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"