michael@0: michael@0: .. currentmodule:: mock michael@0: michael@0: michael@0: .. _magic-methods: michael@0: michael@0: Mocking Magic Methods michael@0: ===================== michael@0: michael@0: .. currentmodule:: mock michael@0: michael@0: :class:`Mock` supports mocking `magic methods michael@0: `_. This allows mock michael@0: objects to replace containers or other objects that implement Python michael@0: protocols. michael@0: michael@0: Because magic methods are looked up differently from normal methods [#]_, 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: 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 [#]_. michael@0: michael@0: .. doctest:: michael@0: 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: One use case for this is for mocking objects used as context managers in a michael@0: `with` statement: michael@0: michael@0: .. doctest:: michael@0: 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: Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they michael@0: are recorded in :attr:`~Mock.mock_calls`. michael@0: michael@0: .. note:: michael@0: 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: 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: ========== michael@0: michael@0: There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. michael@0: michael@0: michael@0: .. class:: MagicMock(*args, **kw) michael@0: michael@0: ``MagicMock`` is a subclass of :class:`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: michael@0: The constructor parameters have the same meaning as for :class:`Mock`. michael@0: 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: .. class:: NonCallableMagicMock(*args, **kw) michael@0: michael@0: A non-callable version of `MagicMock`. michael@0: michael@0: The constructor parameters have the same meaning as for michael@0: :class:`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: The magic methods are setup with `MagicMock` objects, so you can configure them michael@0: and use them in the usual way: michael@0: michael@0: .. doctest:: michael@0: 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: 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: 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: michael@0: .. doctest:: michael@0: 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: 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: michael@0: .. doctest:: michael@0: 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: 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: michael@0: .. doctest:: michael@0: 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: 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: michael@0: .. doctest:: michael@0: 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: ``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: 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: .. [#] 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: .. [#] The function is basically hooked up to the class, but each ``Mock`` michael@0: instance is kept isolated from the others.