How can I patch a method in a class, where the module containing the class is imported using importlib.import_module()
?
The reason for using importlib.import_module()
is because the package to which the module belongs contains a -
, and as I don't control the package I am unable to change that.
I have attempted to patch the method by targeting it directly, and by targeting it though the name of the imported module, but neither works and the assertion in test_someclass.py fails.
File Structure
my-package
| some_module.py
tests
| conftest.py
| test_some_module.py.py
conftest.py
I've tried to patch the method by targeting it directly, and by targeting it though the name of the imported module, but neither works and the assertion in test_someclass.py fails.
import pytest
import importlib
module = importlib.import_module('some-package.some_module')
SomeClass = module.SomeClass
@pytest.fixture(scope='function')
def patch_some_module(mocker):
def some_module():
return "I'm fake :("
path1 = 'some-package.some_module.SomeClass.some_method'
path2 = 'module.SomeClass.some_method'
mocker.patch(path1, some_module)
mocker.patch(path2, some_module)
some_module.py
The module in question contains a class with a method that I wish to mock.
class MyClass:
def my_method(self):
return "I'm real!"
test_some_module.py
from conftest import SomeClass
def test_some_method():
text = SomeClass().some_method()
expected = "I'm fake :("
assert text == expected
Test Failure
As described above, even with my attempts to patch the some_method
method, the test still fails.
================================= test session starts ==================================
platform linux -- Python 3.8.10, pytest-7.0.1, pluggy-1.0.0
rootdir: /home/me/pytest_question
plugins: requests-mock-1.9.3, cov-3.0.0, env-0.6.2, mock-3.7.0
collected 1 item
tests/test_some_module.py F [100%]
======================================= FAILURES =======================================
___________________________________ test_some_method ___________________________________
def test_some_method():
text = SomeClass().some_method()
expected = "I'm fake :("
> assert text == expected
E assert "I'm real!" == "I'm fake :("
E - I'm fake :(
E I'm real!
tests/test_some_module.py:8: AssertionError
=============================== short test summary info ================================
FAILED tests/test_some_module.py::test_some_method - assert "I'm real!" == "I'm fake :("
================================== 1 failed in 0.05s ===================================
CodePudding user response:
You don't seem to be using your fixture in tests/test_some_module.py
Try changing it to the following.
# tests/test_some_module.py
from conftest import SomeClass
@pytest.mark.usefixtures("patch_some_module")
def test_some_method():
text = SomeClass().some_method()
expected = "I'm fake :("
assert text == expected
CodePudding user response:
The answer to this question is that the patch has to be applied to the tests.
That can be done either by passing the fixture into selected tests, for example...
from conftest import SomeClass
def test_some_method(patch_some_module):
text = SomeClass().some_method()
expected = "I'm fake :("
assert text == expected
Or by choosing to apply to patch to all tests.
@pytest.fixture(scope='function', autouse=True)
def patch_some_module(mocker):
def some_module(self):
return "I'm fake :("
path = 'some-package.some_module.SomeClass.some_method'
mocker.patch(path, some_module)