The most common way to patch something in a module seems to be to use something like
from unittest.mock import patch
from mypackage.my_module.my_submodule import function_to_test
@patch('mypackage.my_module.my_submodule.fits.open')
def test_something(self, mock_fits_open)
# ...
mock_fits_open.return_value = some_return_value
function_to_test()
# ...
However, with the value passed to the patch decorator being a string, I don't get lots of the nice benefits from IDE. I can't use parts of the string to jump to definitions. I don't get autocomplete (and an implicit spelling check). Nor full refactoring capabilities. And so on.
Using patch.object
I can get much closer to what I'm looking for.
from unittest.mock import patch
import mypackage.my_module.my_submodule
from mypackage.my_module.my_submodule import function_to_test
@patch.object(mypackage.my_module.my_submodule.fits, 'open')
def test_something(self, mock_fits_open)
# ...
mock_fits_open.return_value = some_return_value
function_to_test()
# ...
However, this still requires the final part of the name of the referenced object is just a string. Is there a (nice) way to patch an object purely on the reference to that object? That is, I would like to be able to do something like
from unittest.mock import patch
import mypackage.my_module.my_submodule
from mypackage.my_module.my_submodule import function_to_test
@patch.reference(mypackage.my_module.my_submodule.fits.open)
def test_something(self, mock_fits_open)
# ...
mock_fits_open.return_value = some_return_value
function_to_test()
# ...
Patching works by replacing in the namespace where the name is looked up.
The underlying logic of mock.patch
is essentially working with a context-managed name shadowing. You could do the same thing manually with:
try
overwriting the namefinally
resetting name back to the original valueTherefore, you fundamentally need to patch on a name, there is no patching a reference directly.