I have a class that contains another class in a variable. Now I want to write a unit-test and define a mock object. Therefore I define a fixture in conftest.py and monkeypatch it with the mock object. I now get a the desired mock object but the inner object is noch the mock object which I defined. The problem ist that my mock that I have created in the fixture (so that the mock returns “Bye”) will not be applied. How can I fix this and is there any better solution? See my minimal example below:
module_a.py
class Connection:
    def get(self, name):
        return f"Hello {name}"
utils.py
from main.module_a import Connection
class Util:
    def __int__(self):
        self.conn: Connection = Connection()
module_main.py
from main.utils import Util
def main() -> str:
    util: Util = Util()
    msg: str = util.conn.get(name="Joe")
    return msg
conftest.py
from unittest.mock import Mock
import pytest
from main.module_a import Connection
from main.utils import Util
@pytest.fixture(scope="function")
def util_mock(monkeypatch):
    conn_mock: Mock = Mock(spec=Connection)
    conn_mock.get.return_value = "Bye"
    util_mock: Mock = Mock(spec=Util, conn=conn_mock)
    monkeypatch.setattr(target="main.module_main.Util", name=util_mock)
    return util_mock
test_module_main.py
from unittest.mock import Mock
from main import module_main
def test_main(util_mock: Mock):
    msg: str = module_main.main()
    test: str = util_mock.conn.get(name="foot")
    assert test == "Bye"  # work right afer fixture insertion
    assert msg == "Bye"  # fails after a new object is created
Advertisement
Answer
Found a solution myself. When a new object is created (Util()) __call__ is triggered and returns a new object of the mock, hence all defined properties are lost. We just need to return the mock object itself with util_mock.return_value = util_mock.
