I'm trying to mock an object that makes some expensive network calls when it's initialized, but the parent class instantiating it isn't recognizing the patch from my unit test.
Some similar questions I've already looked at:
- 1 Doesn't involve any inheritance like in my current situation.
- 2 Has a similar inheritance structure, but it mocks a method instead of a constructor.
Minimal Reproducible Example 3
File Structure
--src
|-- resource.py
|-- family.py
|-- test_child.py
resource.py
class Resource:
def __init__(self):
print("Expensive network call")
def use_resource(self) -> str:
print("Another expensive network call")
return "bar"
family.py
from resource import Resource
class Parent:
def __init__(self):
print("In the Parent constructor.")
self.resource = Resource()
def foo(self):
print("Parent's foo")
print(self.resource.use_resource())
class Child(Parent):
def __init__(self):
super().__init__()
print("In the Child constructor")
def foo(self):
print("Child's foo")
super().foo()
test_child.py
import unittest
from unittest.mock import patch
from family import Child
class TestChild(unittest.TestCase):
@patch('resource.Resource')
def test_foo(self, mock_resource):
mock_resource.return_value.use_resource.return_value = "mock_bar"
child = Child()
child.foo()
mock_resource.return_value.use_resource.assert_called_once()
unittest.main()
Expected Result
Since I'm patching resource.Resource
, I'm expecting to avoid the expensive network calls that normally occur when a Parent
instantiates a Resource
. Theoretically the output of running test_child.py
should look like this:
In the Parent constructor.
In the Child constructor
Child's foo
Parent's foo
mock_bar
Actual Result
However, despite patching resource.Resource
in the test, the Parent
is still instantiating an actual Resource
as evidenced by the presence of the "Expensive network call" messages in the output and the failed assert_called_once
assertion.
In the Parent constructor.
Expensive network call # Should have been patched
In the Child constructor
Child's foo
Parent's foo
Another expensive network call # Should have been patched
bar # Should have been patched
F
======================================================================
FAIL: test_foo (__main__.TestChild)
----------------------------------------------------------------------
Traceback (most recent call last):
File "[REMOVED]\unittest\mock.py", line 1342, in patched
return func(*newargs, **newkeywargs)
File "[REMOVED]\test_child.py", line 13, in test_foo
mock_resource.return_value.use_resource.assert_called_once()
File "[REMOVED]\unittest\mock.py", line 886, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'use_resource' to have been called once. Called 0 times.
----------------------------------------------------------------------
Ran 1 test in 0.005s