michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
michael@0: michael@0: 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:
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:
Calls to magic methods do not appear in method_calls, but they michael@0: are recorded in mock_calls.
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:The full list of supported magic methods is:
michael@0:The following methods are supported in Python 2 but don’t exist in Python 3:
michael@0:The following methods are supported in Python 3 but don’t exist in Python 2:
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:There are two MagicMock variants: MagicMock and NonCallableMagicMock.
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: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: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:
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: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:
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:
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:
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:
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:[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. |
[2] | The function is basically hooked up to the class, but each Mock michael@0: instance is kept isolated from the others. |