python unittest: mocking a dict-like object
I am attempting to do the following:
def test_fn(self):
cool_dict = {}
blah = Mock(spec=DictField, wraps=cool_dict)
blah['key'] = 'val'
print(cool_dict))
return False
Basically, I want to ensure that anything which happens to blah
is allowed for a DictField
, but I want anything that happens to blah
to actually happen to cool_dict
, so I can see assert that it has a certain state.
How can I do this? The above code fails:
FAILED (errors=1)
Error
Traceback (most recent call last):
File "C:\Program Files\Python 3.5\Lib\unittest\case.py", line 59, in testPartExecutor
yield
File "C:\Program Files\Python 3.5\Lib\unittest\case.py", line 605, in run
testMethod()
File "C:\Users\danie01.AD\PycharmProjects\component\component\Default\Functional\pam_team_management\test\test_team_create.py", line 23, in test_populate_info_page
blah['key'] = 'val'
TypeError: 'Mock' object does not support item assignment
I also tried it with a MagicMock
:
def test_populate_info_page(self):
cool_dict = {}
blah = MagicMock(spec=DictField, wraps=cool_dict)
blah['key'] = 'val'
print(cool_dict)
return False
Which didn't fail, but cool_dict was still {}
Solution 1:
In Python, you can also make use of magic methods which are the built-in methods on classes. For dict
objects, you would want to override the __getitem__()
and __setitem__()
magic methods.
As an example, when you make the statement blah['key'] = 'var'
, it's actually calling blah.__setitem__('key', 'var')
. So you'll want to mock those two magic methods, and then check on the status of those mocked methods.
Here's an example of how I might try what you're talking about:
>>> cool_dict = {'key': 'val'}
>>> blah = Mock()
>>> blah.__getitem__ = Mock()
>>> blah.__getitem__.side_effect = cool_dict.__getitem__
>>> blah['key']
'val'
>>> blah.__getitem__.assert_called() # No assertion raised, which means that it was called
>>>
So in this example, the __getitem__()
method of the 'blah' object is the thing you're going to be using a Mock()
to mock, and then you create a side effect: it triggers the same __getitem__()
function on the cool_dict
. After it's been called, you can inspect that Mock afterward to see whether it was called and what it was called with. See Mocking Magic Methods for more context.