learning python mocks here. I need some helps to understand how the patch work when mocking a class.
In the code below, I mocked a class. the function under tests receives the mock and calls a function on it. In my assertions, the class is successfully called, but the function is reported as not being called.
I added a debug print to view the content in the function under tests and it is reported as called.
My expectation is the assertion assert facadeMock.install.called should be true. Why is it not reported as called and how do I achieve this?
Thank you.
install/__init__.py
from .facade import Facade
def main():
f = Facade()
f.install()
print('jf-debug-> "f.install.called": {value}'.format(
value=f.install.called))
test/install_tests.py
import os
import sys
# allow import of package
sys.path.insert(0,
os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from unittest.mock import patch
import install
@patch('install.Facade') # using autospec=True did not change the result
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
install.main()
assert facadeMock.called
assert facadeMock.install is install.Facade.install
assert facadeMock.install.called # <-------------------- Fails here!
output:
============================= test session starts ==============================
platform linux -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/jfl/ubuntu-vim, configfile: pytest.ini
collected 1 item
test/install_tests.py jf-debug-> "f.install.called": True
F
=================================== FAILURES ===================================
________ test_main_with_links_should_call_facade_install_with_link_true ________
facadeMock = <MagicMock name='Facade' id='140679041900864'>
@patch('install.Facade')
def test_main_with_links_should_call_facade_install_with_link_true(facadeMock):
install.main()
assert facadeMock.called
assert facadeMock.install is install.Facade.install
> assert facadeMock.install.called
E AssertionError: assert False
E + where False = <MagicMock name='Facade.install' id='140679042325216'>.called
E + where <MagicMock name='Facade.install' id='140679042325216'> = <MagicMock name='Facade' id='140679041900864'>.install
test/install_tests.py:21: AssertionError
=========================== short test summary info ============================
FAILED test/install_tests.py::test_main_with_links_should_call_facade_install_with_link_true - AssertionError: assert False
============================== 1 failed in 0.09s ===============================
[edit]
Thank you to @chepner and @Daniil Fajnberg for their comments. I found the cause of the problem.
The problem can be reduced at:
install/__init__.py
receives an instance of Facade when calling Facade() in main().
This instance is not the same as the one received in parameters of the test. They are different instances.
to retrieve the instance received in main(), do:
actualInstance = facadeMock.return_value
assert actualInstance.install.called
And it works!
Thank you. That really helps me understand the working of mocks in python.
[/edit]