How do you mock patch a python class and get a new Mock object for each instantiation?
mocking, python, python-mock, python-unittest
Solution
Here's a quick'n'dirty example to get you going:
import mock
import unittest
class ClassToPatch():
def __init__(self, *args):
pass
def some_func(self):
return id(self)
class UUT():
def __init__(self, *args):
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
self.test_property = (resource_1.some_func(), resource_2.some_func())
class TestCase1(unittest.TestCase):
@mock.patch('__main__.ClassToPatch', autospec = True)
def test_1(self, mock1):
ctpMocks = [mock.Mock(), mock.Mock()]
ctpMocks[0].some_func.return_value = "funky"
ctpMocks[1].some_func.return_value = "monkey"
mock1.side_effect = ctpMocks
u = UUT()
self.assertEqual(u.test_property, ("funky", "monkey"))
if __name__ == '__main__':
unittest.main()
I've added `test_property` to UUT so that the unit test does something useful. Now, without the mock `test_property` should be a tuple containing the ids of the two `ClassToPatch` instances. But with the mock it should be the tuple: `("funky", "monkey")`.
I've used the `side_effect` property of the mock object so that a different instance of `ClassToPatch` is returned on each call in the `UUT` initialiser.
Hope this helps.
Edit: Oh, by the way, when I run the unit test I get:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
Problem
OK, I know this is mentioned in the manual, and probably has to do with `side_effect` and/or `return_value`, but a simple, direct example will help me immensely. I have: ``` class ClassToPatch(): def __init__(self, *args): _do_some_init_stuff() def some_func(): _do_stuff() class UUT(): def __init__(self, *args) resource_1 = ClassToPatch() resource_2 = ClassToPatch() ``` Now, I want to unit test the `UUT` class, and mock the `ClassToPatch`. Knowing the `UUT` class will instantiate exactly two `ClassToPatch` objects, I want the Mock framework to return a new Mock object for each instantiation, so I can later assert calls on each separately. How do I achieve this using the `@patch` decorator in a test case? Namely, how to fix the following code sample? ``` class TestCase1(unittest.TestCase): @patch('classToPatch.ClassToPatch',autospec=True) def test_1(self,mock1,mock2): _assert_stuff() ```