michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: Mocking Magic Methods — Mock 1.0.0 documentation michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0: michael@0:
michael@0:

Mocking Magic Methods

michael@0:

Mock supports mocking magic methods. This allows mock michael@0: objects to replace containers or other objects that implement Python michael@0: protocols.

michael@0:

Because magic methods are looked up differently from normal methods [1], this michael@0: support has been specially implemented. This means that only specific magic michael@0: methods are supported. The supported list includes almost all of them. If michael@0: there are any missing that you need please let us know!

michael@0:

You mock magic methods by setting the method you are interested in to a function michael@0: or a mock instance. If you are using a function then it must take self as michael@0: the first argument [2].

michael@0:
>>> def __str__(self):
michael@0: ...     return 'fooble'
michael@0: ...
michael@0: >>> mock = Mock()
michael@0: >>> mock.__str__ = __str__
michael@0: >>> str(mock)
michael@0: 'fooble'
michael@0: 
michael@0: >>> mock = Mock()
michael@0: >>> mock.__str__ = Mock()
michael@0: >>> mock.__str__.return_value = 'fooble'
michael@0: >>> str(mock)
michael@0: 'fooble'
michael@0: 
michael@0: >>> mock = Mock()
michael@0: >>> mock.__iter__ = Mock(return_value=iter([]))
michael@0: >>> list(mock)
michael@0: []
michael@0: 
michael@0:
michael@0:

One use case for this is for mocking objects used as context managers in a michael@0: with statement:

michael@0:
>>> mock = Mock()
michael@0: >>> mock.__enter__ = Mock(return_value='foo')
michael@0: >>> mock.__exit__ = Mock(return_value=False)
michael@0: >>> with mock as m:
michael@0: ...     assert m == 'foo'
michael@0: ...
michael@0: >>> mock.__enter__.assert_called_with()
michael@0: >>> mock.__exit__.assert_called_with(None, None, None)
michael@0: 
michael@0:
michael@0:

Calls to magic methods do not appear in method_calls, but they michael@0: are recorded in mock_calls.

michael@0:
michael@0:

Note

michael@0:

If you use the spec keyword argument to create a mock then attempting to michael@0: set a magic method that isn’t in the spec will raise an AttributeError.

michael@0:
michael@0:

The full list of supported magic methods is:

michael@0:
    michael@0:
  • __hash__, __sizeof__, __repr__ and __str__
  • michael@0:
  • __dir__, __format__ and __subclasses__
  • michael@0:
  • __floor__, __trunc__ and __ceil__
  • michael@0:
  • Comparisons: __cmp__, __lt__, __gt__, __le__, __ge__, michael@0: __eq__ and __ne__
  • michael@0:
  • Container methods: __getitem__, __setitem__, __delitem__, michael@0: __contains__, __len__, __iter__, __getslice__, michael@0: __setslice__, __reversed__ and __missing__
  • michael@0:
  • Context manager: __enter__ and __exit__
  • michael@0:
  • Unary numeric methods: __neg__, __pos__ and __invert__
  • michael@0:
  • The numeric methods (including right hand and in-place variants): michael@0: __add__, __sub__, __mul__, __div__, michael@0: __floordiv__, __mod__, __divmod__, __lshift__, michael@0: __rshift__, __and__, __xor__, __or__, and __pow__
  • michael@0:
  • Numeric conversion methods: __complex__, __int__, __float__, michael@0: __index__ and __coerce__
  • michael@0:
  • Descriptor methods: __get__, __set__ and __delete__
  • michael@0:
  • Pickling: __reduce__, __reduce_ex__, __getinitargs__, michael@0: __getnewargs__, __getstate__ and __setstate__
  • michael@0:
michael@0:

The following methods are supported in Python 2 but don’t exist in Python 3:

michael@0:
    michael@0:
  • __unicode__, __long__, __oct__, __hex__ and __nonzero__
  • michael@0:
  • __truediv__ and __rtruediv__
  • michael@0:
michael@0:

The following methods are supported in Python 3 but don’t exist in Python 2:

michael@0:
    michael@0:
  • __bool__ and __next__
  • michael@0:
michael@0:

The following methods exist but are not supported as they are either in use by michael@0: mock, can’t be set dynamically, or can cause problems:

michael@0:
    michael@0:
  • __getattr__, __setattr__, __init__ and __new__
  • michael@0:
  • __prepare__, __instancecheck__, __subclasscheck__, __del__
  • michael@0:
michael@0:
michael@0:
michael@0:

Magic Mock

michael@0:

There are two MagicMock variants: MagicMock and NonCallableMagicMock.

michael@0:
michael@0:
michael@0: class MagicMock(*args, **kw)
michael@0:

MagicMock is a subclass of Mock with default implementations michael@0: of most of the magic methods. You can use MagicMock without having to michael@0: configure the magic methods yourself.

michael@0:

The constructor parameters have the same meaning as for Mock.

michael@0:

If you use the spec or spec_set arguments then only magic methods michael@0: that exist in the spec will be created.

michael@0:
michael@0: michael@0:
michael@0:
michael@0: class NonCallableMagicMock(*args, **kw)
michael@0:

A non-callable version of MagicMock.

michael@0:

The constructor parameters have the same meaning as for michael@0: MagicMock, with the exception of return_value and michael@0: side_effect which have no meaning on a non-callable mock.

michael@0:
michael@0: michael@0:

The magic methods are setup with MagicMock objects, so you can configure them michael@0: and use them in the usual way:

michael@0:
>>> mock = MagicMock()
michael@0: >>> mock[3] = 'fish'
michael@0: >>> mock.__setitem__.assert_called_with(3, 'fish')
michael@0: >>> mock.__getitem__.return_value = 'result'
michael@0: >>> mock[2]
michael@0: 'result'
michael@0: 
michael@0:
michael@0:

By default many of the protocol methods are required to return objects of a michael@0: specific type. These methods are preconfigured with a default return value, so michael@0: that they can be used without you having to do anything if you aren’t interested michael@0: in the return value. You can still set the return value manually if you want michael@0: to change the default.

michael@0:

Methods and their defaults:

michael@0:
    michael@0:
  • __lt__: NotImplemented
  • michael@0:
  • __gt__: NotImplemented
  • michael@0:
  • __le__: NotImplemented
  • michael@0:
  • __ge__: NotImplemented
  • michael@0:
  • __int__ : 1
  • michael@0:
  • __contains__ : False
  • michael@0:
  • __len__ : 1
  • michael@0:
  • __iter__ : iter([])
  • michael@0:
  • __exit__ : False
  • michael@0:
  • __complex__ : 1j
  • michael@0:
  • __float__ : 1.0
  • michael@0:
  • __bool__ : True
  • michael@0:
  • __nonzero__ : True
  • michael@0:
  • __oct__ : ‘1’
  • michael@0:
  • __hex__ : ‘0x1’
  • michael@0:
  • __long__ : long(1)
  • michael@0:
  • __index__ : 1
  • michael@0:
  • __hash__ : default hash for the mock
  • michael@0:
  • __str__ : default str for the mock
  • michael@0:
  • __unicode__ : default unicode for the mock
  • michael@0:
  • __sizeof__: default sizeof for the mock
  • michael@0:
michael@0:

For example:

michael@0:
>>> mock = MagicMock()
michael@0: >>> int(mock)
michael@0: 1
michael@0: >>> len(mock)
michael@0: 0
michael@0: >>> hex(mock)
michael@0: '0x1'
michael@0: >>> list(mock)
michael@0: []
michael@0: >>> object() in mock
michael@0: False
michael@0: 
michael@0:
michael@0:

The two equality method, __eq__ and __ne__, are special (changed in michael@0: 0.7.2). They do the default equality comparison on identity, using a side michael@0: effect, unless you change their return value to return something else:

michael@0:
>>> MagicMock() == 3
michael@0: False
michael@0: >>> MagicMock() != 3
michael@0: True
michael@0: >>> mock = MagicMock()
michael@0: >>> mock.__eq__.return_value = True
michael@0: >>> mock == 3
michael@0: True
michael@0: 
michael@0:
michael@0:

In 0.8 the __iter__ also gained special handling implemented with a michael@0: side effect. The return value of MagicMock.__iter__ can be any iterable michael@0: object and isn’t required to be an iterator:

michael@0:
>>> mock = MagicMock()
michael@0: >>> mock.__iter__.return_value = ['a', 'b', 'c']
michael@0: >>> list(mock)
michael@0: ['a', 'b', 'c']
michael@0: >>> list(mock)
michael@0: ['a', 'b', 'c']
michael@0: 
michael@0:
michael@0:

If the return value is an iterator, then iterating over it once will consume michael@0: it and subsequent iterations will result in an empty list:

michael@0:
>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])
michael@0: >>> list(mock)
michael@0: ['a', 'b', 'c']
michael@0: >>> list(mock)
michael@0: []
michael@0: 
michael@0:
michael@0:

MagicMock has all of the supported magic methods configured except for some michael@0: of the obscure and obsolete ones. You can still set these up if you want.

michael@0:

Magic methods that are supported but not setup by default in MagicMock are:

michael@0:
    michael@0:
  • __cmp__
  • michael@0:
  • __getslice__ and __setslice__
  • michael@0:
  • __coerce__
  • michael@0:
  • __subclasses__
  • michael@0:
  • __dir__
  • michael@0:
  • __format__
  • michael@0:
  • __get__, __set__ and __delete__
  • michael@0:
  • __reversed__ and __missing__
  • michael@0:
  • __reduce__, __reduce_ex__, __getinitargs__, __getnewargs__, michael@0: __getstate__ and __setstate__
  • michael@0:
  • __getformat__ and __setformat__
  • michael@0:
michael@0:
michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
[1]Magic methods should be looked up on the class rather than the michael@0: instance. Different versions of Python are inconsistent about applying this michael@0: rule. The supported protocol methods should work with all supported versions michael@0: of Python.
michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
[2]The function is basically hooked up to the class, but each Mock michael@0: instance is kept isolated from the others.
michael@0:
michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0:
michael@0:

Table Of Contents

michael@0: michael@0: michael@0:

Previous topic

michael@0:

Sentinel

michael@0:

Next topic

michael@0:

Getting Started with Mock

michael@0:

This Page

michael@0: michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0: michael@0: michael@0: michael@0: