I feel like this may be relatively simple, but I'm pulling my hair out to get this working. I'd like to mock an entire class, and then specify the return value for one of this class's methods.
I already looked here, at several other questions, and of course in the docs. I'm still unable to get this to work. Please see my simple example below.
Contents of directory tmp:
tmp
├── __init__.py
├── my_module.py
└── test_my_module.py
Contents of my_module.py:
class MyClass:
def __init__(self):
# Do expensive operations that will be mocked in testing.
self.a = 7
def my_method(self):
# For sake of simple example, always return 1.
return 1
def create_class_call_method():
"""Create MyClass instance and call its my_method method, returning
the result."""
instance = MyClass()
value = instance.my_method()
return value
Contents of test_my_module.py:
import unittest
from unittest.mock import patch, Mock
from tmp import my_module
class MyClassTestCase(unittest.TestCase):
def test_create_class_call_method(self):
# Attempt to patch MyClass as well as specify a return_value for
# the my_method method (spoiler: this doesn't work)
with patch('tmp.my_module.MyClass',
my_method=Mock(return_value=2)):
value = my_module.create_class_call_method()
self.assertEqual(value, 2)
if __name__ == '__main__':
unittest.main()
Results of running test_my_module.py:
2 != <MagicMock name='MyClass().my_method()' id='140234477124048'>
Expected :<MagicMock name='MyClass().my_method()' id='140234477124048'>
Actual :2
Some other things I've tried:
- Rather than
..., my_method=Mock(return_value=2))in thepatchstatement, unpack a dictionary like so:**{'my_method.return_value': 2} - Nested
with patchstatements. Outer statement is simple likewith patch('tmp.my_module.MyClass'):, inner statement attempts to patchmy_methodlike so:with patch('tmp.my_module.MyClass.my_method, return_value=2) - Use patch decorators instead of context managers
- Change patch statement to
with patch('tmp.my_module.MyClass') as p:and then inside thewithstatement, try to setplike so:p.evaluate = Mock(return_value=2)
Any help is appreciated, thank you.
classmethodvia the@classmethoddecorator and keep it inside the class. (Though it will act a little different than what you implemented). Well worded question.create_class_call_methodis slightly more complicated, and is actually used by a different class, which creates an object and calls one of its methods. So I don't think I can make it aclassmethod