diff options
author | Michael Foord <michael@voidspace.org.uk> | 2012-01-26 02:01:54 +0000 |
---|---|---|
committer | Michael Foord <michael@voidspace.org.uk> | 2012-01-26 02:01:54 +0000 |
commit | ffa680d77bfee389c24b07adce8996c6316f8ca3 (patch) | |
tree | 567233de946e934a8edfec19c66d66b872a95331 | |
parent | 0fe1de2ec7445b298967833dfde219d7ec30d5a1 (diff) | |
download | mock-ffa680d77bfee389c24b07adce8996c6316f8ca3.tar.gz |
Extended examples for mocksignature
-rw-r--r-- | docs/mocksignature.txt | 110 | ||||
-rw-r--r-- | mock.py | 3 |
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. @@ -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. |