summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Foord <michael@voidspace.org.uk>2012-01-26 02:01:54 +0000
committerMichael Foord <michael@voidspace.org.uk>2012-01-26 02:01:54 +0000
commitffa680d77bfee389c24b07adce8996c6316f8ca3 (patch)
tree567233de946e934a8edfec19c66d66b872a95331
parent0fe1de2ec7445b298967833dfde219d7ec30d5a1 (diff)
downloadmock-ffa680d77bfee389c24b07adce8996c6316f8ca3.tar.gz
Extended examples for mocksignature
-rw-r--r--docs/mocksignature.txt110
-rw-r--r--mock.py3
2 files changed, 88 insertions, 25 deletions
diff --git a/docs/mocksignature.txt b/docs/mocksignature.txt
index e53bfa3..1ad7d86 100644
--- a/docs/mocksignature.txt
+++ b/docs/mocksignature.txt
@@ -14,16 +14,16 @@ any way and you have to manually check that they were called correctly. If your
code calls functions or methods with the wrong number of arguments then mocks
don't complain.
-The solution to this is ``mocksignature``, which creates functions with the
+The solution to this is `mocksignature`, which creates functions with the
same signature as the original, but delegating to a mock. You can interrogate
the mock in the usual way to check it has been called with the *right*
arguments, but if it is called with the wrong number of arguments it will
-raise a ``TypeError`` in the same way your production code would.
+raise a `TypeError` in the same way your production code would.
Another advantage is that your mocked objects are real functions, which can
be useful when your code uses
-`inspect <http://docs.python.org/library/inspect.html>`_ or depends on functions
-being functions.
+`inspect <http://docs.python.org/library/inspect.html>`_ or depends on
+functions being function objects.
.. function:: mocksignature(func, mock=None, skipfirst=False)
@@ -33,6 +33,9 @@ being functions.
If you don't pass in a `mock` then one will be created for you.
+ Functions returned by `mocksignature` have many of the same attributes
+ and assert methods as a mock object.
+
The mock is set as the `mock` attribute of the returned function for easy
access.
@@ -42,14 +45,68 @@ being functions.
When used with callable objects (instances) it copies the signature of the
`__call__` method.
-``mocksignature`` will work out if it is mocking the signature of a method on
-an instance or a method on a class and do the "right thing" with the ``self``
+`mocksignature` will work out if it is mocking the signature of a method on
+an instance or a method on a class and do the "right thing" with the `self`
argument in both cases.
Because of a limitation in the way that arguments are collected by functions
-created by ``mocksignature`` they are *always* passed as positional arguments
+created by `mocksignature` they are *always* passed as positional arguments
(including defaults) and not keyword arguments.
+
+mocksignature api
+-----------------
+
+Although the objects returned by `mocksignature` api are real function objects,
+they have much of the same api as the :class:`Mock` class. This includes the
+assert methods:
+
+.. doctest::
+
+ >>> def func(a, b, c):
+ ... pass
+ ...
+ >>> func2 = mocksignature(func)
+ >>> func2.called
+ False
+ >>> func2.return_value = 3
+ >>> func2(1, 2, 3)
+ 3
+ >>> func2.called
+ True
+ >>> func2.assert_called_once_with(1, 2, 3)
+ >>> func2.assert_called_with(1, 2, 4)
+ Traceback (most recent call last):
+ ...
+ AssertionError: Expected call: mock(1, 2, 4)
+ Actual call: mock(1, 2, 3)
+ >>> func2.call_count
+ 1
+ >>> func2.side_effect = IndexError
+ >>> func2(4, 5, 6)
+ Traceback (most recent call last):
+ ...
+ IndexError
+
+The mock object that is being delegated to is available as the `mock` attribute
+of the function created by `mocksignature`.
+
+.. doctest::
+
+ >>> func2.mock.mock_calls
+ [call(1, 2, 3), call(4, 5, 6)]
+
+The methods and attributes available on functions returned by `mocksignature`
+are:
+
+ :meth:`~Mock.assert_any_call`, :meth:`~Mock.assert_called_once_with`,
+ :meth:`~Mock.assert_called_with`', :meth:`~Mock.assert_has_calls`,
+ :attr:`~Mock.call_args', :attr:`call_args_list`,
+ :attr:`call_count`, :attr:`called`, :attr:`method_calls`, 'mock',
+ :attr:`mock_calls`, :meth:`~Mock.reset_mock`, :attr:`return_value`, and
+ :attr:`side_effect`.
+
+
Example use
-----------
@@ -67,16 +124,16 @@ Basic use
Traceback (most recent call last):
...
TypeError: <lambda>() takes at least 2 arguments (0 given)
- >>> mock.return_value = 'some value'
+ >>> function.return_value = 'some value'
>>> function(1, 2, 'foo')
'some value'
- >>> function.mock.assert_called_with(1, 2, 'foo')
+ >>> function.assert_called_with(1, 2, 'foo')
Keyword arguments
~~~~~~~~~~~~~~~~~
-Note that arguments to functions created by ``mocksignature`` are always passed
+Note that arguments to functions created by `mocksignature` are always passed
in to the underlying mock by position even when called with keywords:
.. doctest::
@@ -85,17 +142,21 @@ in to the underlying mock by position even when called with keywords:
... pass
...
>>> function = mocksignature(function)
- >>> function.mock.return_value = None
+ >>> function.return_value = None
>>> function(1, 2)
- >>> function.mock.assert_called_with(1, 2, None)
+ >>> function.assert_called_with(1, 2, None)
Mocking methods and self
~~~~~~~~~~~~~~~~~~~~~~~~
-When you use ``mocksignature`` to replace a method on a class then ``self``
+When you use `mocksignature` to replace a method on a class then `self`
will be included in the method signature - and you will need to include
-the instance when you do your asserts:
+the instance when you do your asserts.
+
+As a curious factor of the way Python (2) wraps methods fetched from a class,
+we can *get* the `return_value` from a function set on a class, but we can't
+set it. We have to do this through the exposed `mock` attribute instead:
.. doctest::
@@ -111,9 +172,10 @@ the instance when you do your asserts:
...
TypeError: <lambda>() takes at least 4 arguments (1 given)
>>> instance.method(1, 2, 3)
- >>> instance.method.mock.assert_called_with(instance, 1, 2, 3)
+ >>> instance.method.assert_called_with(instance, 1, 2, 3)
-When you use ``mocksignature`` on instance methods ``self`` isn't included:
+When you use `mocksignature` on instance methods `self` isn't included (and we
+can set the `return_value` etc directly):
.. doctest::
@@ -123,9 +185,9 @@ When you use ``mocksignature`` on instance methods ``self`` isn't included:
...
>>> instance = SomeClass()
>>> instance.method = mocksignature(instance.method)
- >>> instance.method.mock.return_value = None
+ >>> instance.method.return_value = None
>>> instance.method(1, 2, 3)
- >>> instance.method.mock.assert_called_with(1, 2, 3)
+ >>> instance.method.assert_called_with(1, 2, 3)
mocksignature with classes
@@ -142,8 +204,8 @@ method.
...
>>> MockSomething = mocksignature(Something)
>>> instance = MockSomething(10, 9)
- >>> assert instance is MockSomething.mock.return_value
- >>> MockSomething.mock.assert_called_with(10, 9)
+ >>> assert instance is MockSomething.return_value
+ >>> MockSomething.assert_called_with(10, 9)
>>> MockSomething()
Traceback (most recent call last):
...
@@ -153,6 +215,7 @@ Because the object returned by `mocksignature` is a function rather than a
`Mock` you lose the other capabilities of `Mock`, like dynamic attribute
creation.
+
mocksignature with callable objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -168,20 +231,17 @@ When used with a callable object `mocksignature` copies the signature of the
>>> something = Something()
>>> mock_something = mocksignature(something)
>>> result = mock_something(10, 9)
- >>> mock_something.mock.assert_called_with(10, 9)
+ >>> mock_something.assert_called_with(10, 9)
>>> mock_something()
Traceback (most recent call last):
...
TypeError: <lambda>() takes at least 2 arguments (0 given)
-Because the object returned by `mocksignature` is a function rather than a
-`Mock` you lose the other capabilities of `Mock`, like dynamic attribute
-creation.
mocksignature argument to patch
-------------------------------
-``mocksignature`` is available as a keyword argument to :func:`patch` or
+`mocksignature` is available as a keyword argument to :func:`patch` or
:func:`patch.object`. It can be used with functions / methods / classes and
callable objects.
diff --git a/mock.py b/mock.py
index c33e46a..75a1959 100644
--- a/mock.py
+++ b/mock.py
@@ -314,6 +314,9 @@ def mocksignature(func, mock=None, skipfirst=False):
The mock is set as the `mock` attribute of the returned function for easy
access.
+ Functions returned by `mocksignature` have many of the same attributes
+ and assert methods as a mock object.
+
`mocksignature` can also be used with classes. It copies the signature of
the `__init__` method.