Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a dictionary in Python

Tags:

python

mocking

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?

like image 379
James Lin Avatar asked Jul 11 '16 04:07

James Lin


People also ask

How do you make a mock in Python?

If you want to mock an object for the duration of your entire test function, you can use patch() as a function decorator. These functions are now in their own file, separate from their tests. Next, you'll re-create your tests in a file called tests.py .

How does mock in Python work?

mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. unittest. mock provides a core Mock class removing the need to create a host of stubs throughout your test suite.


3 Answers

How to mock a dictionary in Python is a good/direct question someone else can search, so:

  1. I suggest MagicMock instead of Mock
  2. 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:

  • How to let MagicMock behave like a dict?
  • Understanding __getitem__ method

=== EDIT ===

As a function for direct copy/pasting

def mock_dict(d):   m = MagicMock()   m.__getitem__.side_effect = d.__getitem__   return m 
like image 52
Manu Avatar answered Sep 22 '22 15:09

Manu


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 Mocks 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.

like image 31
erandros Avatar answered Sep 21 '22 15:09

erandros


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"
like image 43
Peter Boone Avatar answered Sep 20 '22 15:09

Peter Boone