Mock returning an ImportError when patching a module that's imported
I'm not sure if this duplicates your setup exactly, but here is a simple test case that worked for me.
The directory setup is:
c:\work
\control
__init__.py
scripts.py
\tests
__inti__.py
mytests.py
and c:\work is on sys.path
In the module scripts.py:
def identity(x):
return x
def do_identity(x):
return identity(x)
In mytests.py:
import unittest
from unittest.mock import patch
from control import scripts
class MyTest(unittest.TestCase):
def test_patch(self):
with patch('control.scripts.identity') as mymock:
mymock.return_value = 99
self.assertEqual(scripts.do_identity(1), 99)
def test_no_patch(self):
self.assertEqual(scripts.do_identity(1), 1)
if __name__ == "__main__":
unittest.main()
So what I am trying to do here is to mock the function 'identity' which is called by the function 'do_identity'. Both functions are in the 'scripts' module. This test runs with no errors or failures.
And I can run this from any directory as:
c:\any_directory> python c:\work\control\tests\mytests.py
For more complicated project structure (or if you want to make te mock parts shorter), I come up with a tricky solution, because I needed a seperation between the Logic and the UI.
My structure looks something like this:
├───sourceroot
│ ├───python_pkg
│ │ ├───__init__
│ │ └───subpkg
│ │ ├───__init__
│ │ ├───logic
│ │ │ ├───lpkg1
│ │ │ │ ├───__init__
│ │ │ │ ├───file1.py
│ │ │ │ └───file2.py
│ │ │ ├───lpkg2
│ │ │ │ ├───__init__
│ │ │ │ ├───file3.py
│ │ │ │ └───file4.py
│ │ │ ├───__init__
│ │ │ └───file.py
│ │ └───ui
│ │ ├───uipkg3
│ │ │ ├───__init__
│ │ │ ├───file_ui1.py
│ │ │ └───file_ui2.py
│ │ ├───uipkg4
│ │ │ ├───__init__
│ │ │ ├───file_ui3.py
│ │ │ └───file_ui4.py
│ │ ├───__init__
│ │ └───file_ui.py
│ └───packages
│ └───some_3rd_party_packages
├───srcfiles_from_3rd_parties
└───tests
└───unit_tests_py
├───__init__
└───test.py
I had to reference on the file.py and file1.py from test.py.
To see the sourceroot from the test.py-file I write the following into the sourceroot/tests/unit_test_py/__init__
import sys
import os
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')))
After the Initialisation and adding the sourceroot to the paths (where Python will look up) the test.py
class is ready to Edit:
Before:
import mock
from sourceroot.python_pkg.subpkg.logic import file
from sourceroot.python_pkg.subpkg.logic.lpkg1.file1 import SomeClassFromFile1 as SCF1
class Test_test1(object):
def test_first(self, mocker):
mocker.patch('sourceroot.python_pkg.subpkg.logic.lpkg1.file1.some_function_which_SCF1_calls')
mocker.patch('sourceroot.python_pkg.subpkg.logic.file.SomeClassInFile.some_function_which_SomeClassInFile_calls')
SCF1.some_function_in_SCF1()
expected_information = True
assert SCF1.is_something() == expected_information
After:
import mock
from sourceroot.python_pkg.subpkg.logic import file
from sourceroot.python_pkg.subpkg.logic.lpkg1.file1 import SomeClassFromFile1 as SCF1
class Test_test1(object):
def test_first(self, mocker):
mocker.patch.object(SCF1, 'some_function_which_SCF1_calls')
mocker.patch.object(file.SomeClassInFile, 'some_function_which_SomeClassInFile_calls')
SCF1.some_function_in_SCF1()
expected_information = True
assert SCF1.is_something() == expected_information