I need to test a function that uses a lot of legacy code that I can't touch now. I patched the legacy class (LegacyClass
) with the @patch
decorator on my test class. The legacy class has a method get_dict(args)
that returns a dictionary and for my test purpose I need to mock the return of get_dict(args)
with a static dictionary.
class_to_test.py
from my_module import LegacyClass
class ClassToTest():
self.legacy=LegacyClass() #I can't touch this part noe
def method_to_test(self):
d = self.legacy.get_dict()
if d['data']['value'] == 1:
return True
else:
return None
test.py
@patch('my_module.LegacyClass')
class TestClass(unittest.TestCase):
def test_case(self, legacy_mock):
legacy_mock.get_dict = MagicMock(return_value={'data': {'value': 1}})
ctt = ClassToTest()
assert ctt.method_to_test()
In my function, I use the returned dict
to check if a specific value
is present otherwise I return a default value. The function returns the default value even if the expected value is 1
as in the above example. It seems that the mock of get_dict
doesn't work or I do something wrong.
Updated
The main problem is that you trying to mock a property instance after initialization. In your case, the object will always be initialized during import. So the flow looks like:
import ClassToTest -> import LegacyClass -> LegacyClass.__init__ -> mock.patch(...)
. You need to mock class before initialization if you want to skip all side-effects
Here is an example:
$ tree
# output:
├── src
│ ├── __init__.py
│ ├── class_to_test.py
│ ├── my_module.py
├── test_example.py
src/my_module.py:
class LegacyClass:
def __init__(self) -> None:
raise Exception('check side-effects')
def get_dict(self) -> dict:
raise NotImplemented()
src/class_to_test.py:
from src.my_module import LegacyClass
class ClassToTest:
legacy = LegacyClass()
def method_to_test(self):
d = self.legacy.get_dict()
return d['data']['value'] == 1
test_example.py:
from unittest import TestCase, mock
class TestExample(TestCase):
def test_get_dict(self):
with mock.patch('src.my_module.LegacyClass'):
from src.class_to_test import ClassToTest
to_test = ClassToTest()
self.assertTrue(isinstance(to_test.legacy, mock.Mock))
to_test.legacy.get_dict = mock.Mock(return_value={'data': {'value': 1}})
self.assertTrue(to_test.method_to_test())
Let's check:
pytest test_example.py
============================================================================================= test session starts =============================================================================================
...
collected 1 item
test_example.py . [100%]
============================================================================================== 1 passed in 0.03s ==============================================================================================