mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-11-19 02:13:04 +00:00
259 lines
7.7 KiB
Plaintext
259 lines
7.7 KiB
Plaintext
|
|
||
|
.. currentmodule:: mock
|
||
|
|
||
|
|
||
|
.. _magic-methods:
|
||
|
|
||
|
Mocking Magic Methods
|
||
|
=====================
|
||
|
|
||
|
.. currentmodule:: mock
|
||
|
|
||
|
:class:`Mock` supports mocking `magic methods
|
||
|
<http://www.ironpythoninaction.com/magic-methods.html>`_. This allows mock
|
||
|
objects to replace containers or other objects that implement Python
|
||
|
protocols.
|
||
|
|
||
|
Because magic methods are looked up differently from normal methods [#]_, this
|
||
|
support has been specially implemented. This means that only specific magic
|
||
|
methods are supported. The supported list includes *almost* all of them. If
|
||
|
there are any missing that you need please let us know!
|
||
|
|
||
|
You mock magic methods by setting the method you are interested in to a function
|
||
|
or a mock instance. If you are using a function then it *must* take ``self`` as
|
||
|
the first argument [#]_.
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> def __str__(self):
|
||
|
... return 'fooble'
|
||
|
...
|
||
|
>>> mock = Mock()
|
||
|
>>> mock.__str__ = __str__
|
||
|
>>> str(mock)
|
||
|
'fooble'
|
||
|
|
||
|
>>> mock = Mock()
|
||
|
>>> mock.__str__ = Mock()
|
||
|
>>> mock.__str__.return_value = 'fooble'
|
||
|
>>> str(mock)
|
||
|
'fooble'
|
||
|
|
||
|
>>> mock = Mock()
|
||
|
>>> mock.__iter__ = Mock(return_value=iter([]))
|
||
|
>>> list(mock)
|
||
|
[]
|
||
|
|
||
|
One use case for this is for mocking objects used as context managers in a
|
||
|
`with` statement:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> mock = Mock()
|
||
|
>>> mock.__enter__ = Mock(return_value='foo')
|
||
|
>>> mock.__exit__ = Mock(return_value=False)
|
||
|
>>> with mock as m:
|
||
|
... assert m == 'foo'
|
||
|
...
|
||
|
>>> mock.__enter__.assert_called_with()
|
||
|
>>> mock.__exit__.assert_called_with(None, None, None)
|
||
|
|
||
|
Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they
|
||
|
are recorded in :attr:`~Mock.mock_calls`.
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
If you use the `spec` keyword argument to create a mock then attempting to
|
||
|
set a magic method that isn't in the spec will raise an `AttributeError`.
|
||
|
|
||
|
The full list of supported magic methods is:
|
||
|
|
||
|
* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__``
|
||
|
* ``__dir__``, ``__format__`` and ``__subclasses__``
|
||
|
* ``__floor__``, ``__trunc__`` and ``__ceil__``
|
||
|
* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``,
|
||
|
``__eq__`` and ``__ne__``
|
||
|
* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``,
|
||
|
``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``,
|
||
|
``__setslice__``, ``__reversed__`` and ``__missing__``
|
||
|
* Context manager: ``__enter__`` and ``__exit__``
|
||
|
* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__``
|
||
|
* The numeric methods (including right hand and in-place variants):
|
||
|
``__add__``, ``__sub__``, ``__mul__``, ``__div__``,
|
||
|
``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``,
|
||
|
``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__``
|
||
|
* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``,
|
||
|
``__index__`` and ``__coerce__``
|
||
|
* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__``
|
||
|
* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``,
|
||
|
``__getnewargs__``, ``__getstate__`` and ``__setstate__``
|
||
|
|
||
|
|
||
|
The following methods are supported in Python 2 but don't exist in Python 3:
|
||
|
|
||
|
* ``__unicode__``, ``__long__``, ``__oct__``, ``__hex__`` and ``__nonzero__``
|
||
|
* ``__truediv__`` and ``__rtruediv__``
|
||
|
|
||
|
The following methods are supported in Python 3 but don't exist in Python 2:
|
||
|
|
||
|
* ``__bool__`` and ``__next__``
|
||
|
|
||
|
The following methods exist but are *not* supported as they are either in use by
|
||
|
mock, can't be set dynamically, or can cause problems:
|
||
|
|
||
|
* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__``
|
||
|
* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__``
|
||
|
|
||
|
|
||
|
|
||
|
Magic Mock
|
||
|
==========
|
||
|
|
||
|
There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`.
|
||
|
|
||
|
|
||
|
.. class:: MagicMock(*args, **kw)
|
||
|
|
||
|
``MagicMock`` is a subclass of :class:`Mock` with default implementations
|
||
|
of most of the magic methods. You can use ``MagicMock`` without having to
|
||
|
configure the magic methods yourself.
|
||
|
|
||
|
The constructor parameters have the same meaning as for :class:`Mock`.
|
||
|
|
||
|
If you use the `spec` or `spec_set` arguments then *only* magic methods
|
||
|
that exist in the spec will be created.
|
||
|
|
||
|
|
||
|
.. class:: NonCallableMagicMock(*args, **kw)
|
||
|
|
||
|
A non-callable version of `MagicMock`.
|
||
|
|
||
|
The constructor parameters have the same meaning as for
|
||
|
:class:`MagicMock`, with the exception of `return_value` and
|
||
|
`side_effect` which have no meaning on a non-callable mock.
|
||
|
|
||
|
The magic methods are setup with `MagicMock` objects, so you can configure them
|
||
|
and use them in the usual way:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> mock = MagicMock()
|
||
|
>>> mock[3] = 'fish'
|
||
|
>>> mock.__setitem__.assert_called_with(3, 'fish')
|
||
|
>>> mock.__getitem__.return_value = 'result'
|
||
|
>>> mock[2]
|
||
|
'result'
|
||
|
|
||
|
By default many of the protocol methods are required to return objects of a
|
||
|
specific type. These methods are preconfigured with a default return value, so
|
||
|
that they can be used without you having to do anything if you aren't interested
|
||
|
in the return value. You can still *set* the return value manually if you want
|
||
|
to change the default.
|
||
|
|
||
|
Methods and their defaults:
|
||
|
|
||
|
* ``__lt__``: NotImplemented
|
||
|
* ``__gt__``: NotImplemented
|
||
|
* ``__le__``: NotImplemented
|
||
|
* ``__ge__``: NotImplemented
|
||
|
* ``__int__`` : 1
|
||
|
* ``__contains__`` : False
|
||
|
* ``__len__`` : 1
|
||
|
* ``__iter__`` : iter([])
|
||
|
* ``__exit__`` : False
|
||
|
* ``__complex__`` : 1j
|
||
|
* ``__float__`` : 1.0
|
||
|
* ``__bool__`` : True
|
||
|
* ``__nonzero__`` : True
|
||
|
* ``__oct__`` : '1'
|
||
|
* ``__hex__`` : '0x1'
|
||
|
* ``__long__`` : long(1)
|
||
|
* ``__index__`` : 1
|
||
|
* ``__hash__`` : default hash for the mock
|
||
|
* ``__str__`` : default str for the mock
|
||
|
* ``__unicode__`` : default unicode for the mock
|
||
|
* ``__sizeof__``: default sizeof for the mock
|
||
|
|
||
|
For example:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> mock = MagicMock()
|
||
|
>>> int(mock)
|
||
|
1
|
||
|
>>> len(mock)
|
||
|
0
|
||
|
>>> hex(mock)
|
||
|
'0x1'
|
||
|
>>> list(mock)
|
||
|
[]
|
||
|
>>> object() in mock
|
||
|
False
|
||
|
|
||
|
The two equality method, `__eq__` and `__ne__`, are special (changed in
|
||
|
0.7.2). They do the default equality comparison on identity, using a side
|
||
|
effect, unless you change their return value to return something else:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> MagicMock() == 3
|
||
|
False
|
||
|
>>> MagicMock() != 3
|
||
|
True
|
||
|
>>> mock = MagicMock()
|
||
|
>>> mock.__eq__.return_value = True
|
||
|
>>> mock == 3
|
||
|
True
|
||
|
|
||
|
In `0.8` the `__iter__` also gained special handling implemented with a
|
||
|
side effect. The return value of `MagicMock.__iter__` can be any iterable
|
||
|
object and isn't required to be an iterator:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> mock = MagicMock()
|
||
|
>>> mock.__iter__.return_value = ['a', 'b', 'c']
|
||
|
>>> list(mock)
|
||
|
['a', 'b', 'c']
|
||
|
>>> list(mock)
|
||
|
['a', 'b', 'c']
|
||
|
|
||
|
If the return value *is* an iterator, then iterating over it once will consume
|
||
|
it and subsequent iterations will result in an empty list:
|
||
|
|
||
|
.. doctest::
|
||
|
|
||
|
>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])
|
||
|
>>> list(mock)
|
||
|
['a', 'b', 'c']
|
||
|
>>> list(mock)
|
||
|
[]
|
||
|
|
||
|
``MagicMock`` has all of the supported magic methods configured except for some
|
||
|
of the obscure and obsolete ones. You can still set these up if you want.
|
||
|
|
||
|
Magic methods that are supported but not setup by default in ``MagicMock`` are:
|
||
|
|
||
|
* ``__cmp__``
|
||
|
* ``__getslice__`` and ``__setslice__``
|
||
|
* ``__coerce__``
|
||
|
* ``__subclasses__``
|
||
|
* ``__dir__``
|
||
|
* ``__format__``
|
||
|
* ``__get__``, ``__set__`` and ``__delete__``
|
||
|
* ``__reversed__`` and ``__missing__``
|
||
|
* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``,
|
||
|
``__getstate__`` and ``__setstate__``
|
||
|
* ``__getformat__`` and ``__setformat__``
|
||
|
|
||
|
|
||
|
|
||
|
------------
|
||
|
|
||
|
.. [#] Magic methods *should* be looked up on the class rather than the
|
||
|
instance. Different versions of Python are inconsistent about applying this
|
||
|
rule. The supported protocol methods should work with all supported versions
|
||
|
of Python.
|
||
|
.. [#] The function is basically hooked up to the class, but each ``Mock``
|
||
|
instance is kept isolated from the others.
|