I have 1 file which loads a particular resource ( from a file ) that takes a while to load.
I have a function in another file which uses that resource by importing it first. When that resource is first imported, it loads and takes a bit.
However, when I'm testing that function that requires that resource, I wanna pass it another smaller resource.
Unfortunately, there aren't any major refactors I'm able to do to either file1.py
or file2.py
. Is there a solution using pytest
? I haven't been able to get it working.
def load_resource():
print("Loading big resource...")
return {"key": "big resource"}
resource = load_resource()
from file1 import resource
def my_func():
return resource["key"]
import pytest
@pytest.fixture(autouse=True)
def mock_load_resource(monkeypatch):
def mock_resource():
return {'key': 'mocked_value'}
monkeypatch.setattr('file1', 'load_resource', mock_resource)
monkeypatch.setattr('file1', 'resource', mock_resource())
def test_my_function():
from file2 import my_func
result = my_func()
assert result == 'mocked_value'
You cannot patch a global function without first importing that function, so the only way I know to achieve what you need is to mock the entire module.
This can be done by replacing the module in sys.modules
with your mock object:
from unittest.mock import Mock, patch
import pytest
@pytest.fixture(autouse=True)
def mock_load_resource():
def mock_resource():
return {'key': 'mocked_value'}
fake_file1 = Mock()
fake_file1.load_resource = mock_resource
fake_file1.resource = mock_resource()
with patch.dict('sys.modules', {'file1': fake_file1}):
yield
As far as I know, monkeypatch
has no method that would allow that, but you can just use unittest.mock.patch.dict as shown above. This ensures that during the test, the mock will be loaded instead of the real test. After the test, the mock is removed from sys.modules
, and the real module is loaded the next time it is imported.
Of course, any other attribute or function inside the mocked module will also not work, so if you need more functionality from that module inside your test, you may have to do more mocking.