How to mock a dictionary in Python
Question:
Let’s say I have a function like this:
def do_something(dict_obj):
# access to the dict_obj then do some stuff
eg.
if dict_obj['doors']:
do_something_with_doors()
map_car_make(dict_obj['make'])
...
if dict_obj['is_active']:
do_something_else()
I want to mock the dict_obj
to have is_active
element and don’t care the rest, how do I do that?
Answers:
You can use dict.get method to return the default value of your choice that can mock the existence of is_active entry.
How to mock a dictionary in Python is a good/direct question someone else can search, so:
- I suggest MagicMock instead of Mock
- Overload the
__getitem__
from unittest.mock import MagicMock
m = MagicMock()
d = {'key_1': 'value'}
m.__getitem__.side_effect = d.__getitem__
# dict behaviour
m['key_1'] # => 'value'
m['key_2'] # => raise KeyError
# mock behaviour
m.foo(42)
m.foo.assert_called_once_with(43) # => raise AssertionError
Related Questions:
=== EDIT ===
As a function for direct copy/pasting
def mock_dict(d):
m = MagicMock()
m.__getitem__.side_effect = d.__getitem__
return m
You can use this to make a mock behave like a dictionary:
mock = mocker.MagicMock()
mock.__getitem__.side_effect = lambda x: getattr(mock, x)
With that code mock['some_property']
equals to mock.some_property
.
This way you can still use your autogenerated Mock
s so useful for assertions, which is why I didn’t like the accepted answer.
If you still need to access the methods of the dictionary then the code will need further work.
For anyone coming across this later, there is also mock.patch.dict
which can be used as a context manager, decorator, or class decorator.
For example:
from mock import patch
foo = {}
@patch.dict(foo, {"is_active": True})
def test():
assert foo['is_active'] == True
Or to mock os.environ
which is how I came across this question:
import os
from mock import patch
@patch.dict("os.environ", {"FOO": "BAR"})
def test_env():
assert os.environ['FOO'] == "BAR"
Maybe I misunderstood a question, but what about just default dict?
You can safely access any keys now.
from collections import defaultdict
dd = defaultdict(str, is_active=True)
... # Perform code calls
# And check it
assert dd['is_active'] == True
Let’s say I have a function like this:
def do_something(dict_obj):
# access to the dict_obj then do some stuff
eg.
if dict_obj['doors']:
do_something_with_doors()
map_car_make(dict_obj['make'])
...
if dict_obj['is_active']:
do_something_else()
I want to mock the dict_obj
to have is_active
element and don’t care the rest, how do I do that?
You can use dict.get method to return the default value of your choice that can mock the existence of is_active entry.
How to mock a dictionary in Python is a good/direct question someone else can search, so:
- I suggest MagicMock instead of Mock
- Overload the
__getitem__
from unittest.mock import MagicMock
m = MagicMock()
d = {'key_1': 'value'}
m.__getitem__.side_effect = d.__getitem__
# dict behaviour
m['key_1'] # => 'value'
m['key_2'] # => raise KeyError
# mock behaviour
m.foo(42)
m.foo.assert_called_once_with(43) # => raise AssertionError
Related Questions:
=== EDIT ===
As a function for direct copy/pasting
def mock_dict(d):
m = MagicMock()
m.__getitem__.side_effect = d.__getitem__
return m
You can use this to make a mock behave like a dictionary:
mock = mocker.MagicMock()
mock.__getitem__.side_effect = lambda x: getattr(mock, x)
With that code mock['some_property']
equals to mock.some_property
.
This way you can still use your autogenerated Mock
s so useful for assertions, which is why I didn’t like the accepted answer.
If you still need to access the methods of the dictionary then the code will need further work.
For anyone coming across this later, there is also mock.patch.dict
which can be used as a context manager, decorator, or class decorator.
For example:
from mock import patch
foo = {}
@patch.dict(foo, {"is_active": True})
def test():
assert foo['is_active'] == True
Or to mock os.environ
which is how I came across this question:
import os
from mock import patch
@patch.dict("os.environ", {"FOO": "BAR"})
def test_env():
assert os.environ['FOO'] == "BAR"
Maybe I misunderstood a question, but what about just default dict?
You can safely access any keys now.
from collections import defaultdict
dd = defaultdict(str, is_active=True)
... # Perform code calls
# And check it
assert dd['is_active'] == True