diff options
Diffstat (limited to 'python/mock-1.0.0/html/_sources/mocksignature.txt')
-rw-r--r-- | python/mock-1.0.0/html/_sources/mocksignature.txt | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/python/mock-1.0.0/html/_sources/mocksignature.txt b/python/mock-1.0.0/html/_sources/mocksignature.txt new file mode 100644 index 000000000..dbb5019fb --- /dev/null +++ b/python/mock-1.0.0/html/_sources/mocksignature.txt @@ -0,0 +1,262 @@ +mocksignature +============= + +.. currentmodule:: mock + +.. note:: + + :ref:`auto-speccing`, added in mock 0.8, is a more advanced version of + `mocksignature` and can be used for many of the same use cases. + +A problem with using mock objects to replace real objects in your tests is that +:class:`Mock` can be *too* flexible. Your code can treat the mock objects in +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 +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. + +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 function objects. + +.. function:: mocksignature(func, mock=None, skipfirst=False) + + Create a new function with the same signature as `func` that delegates + to `mock`. If `skipfirst` is True the first argument is skipped, useful + for methods where `self` needs to be omitted from the new function. + + 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. + + `mocksignature` can also be used with classes. It copies the signature of + the `__init__` method. + + 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` +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 +(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:`~Mock.call_args_list`, + :attr:`~Mock.call_count`, :attr:`~Mock.called`, + :attr:`~Mock.method_calls`, `mock`, :attr:`~Mock.mock_calls`, + :meth:`~Mock.reset_mock`, :attr:`~Mock.return_value`, and + :attr:`~Mock.side_effect`. + + +Example use +----------- + +Basic use +~~~~~~~~~ + +.. doctest:: + + >>> def function(a, b, c=None): + ... pass + ... + >>> mock = Mock() + >>> function = mocksignature(function, mock) + >>> function() + Traceback (most recent call last): + ... + TypeError: <lambda>() takes at least 2 arguments (0 given) + >>> function.return_value = 'some value' + >>> function(1, 2, 'foo') + 'some value' + >>> function.assert_called_with(1, 2, 'foo') + + +Keyword arguments +~~~~~~~~~~~~~~~~~ + +Note that arguments to functions created by `mocksignature` are always passed +in to the underlying mock by position even when called with keywords: + +.. doctest:: + + >>> def function(a, b, c=None): + ... pass + ... + >>> function = mocksignature(function) + >>> function.return_value = None + >>> function(1, 2) + >>> function.assert_called_with(1, 2, None) + + +Mocking methods and 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. + +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:: + + >>> class SomeClass(object): + ... def method(self, a, b, c=None): + ... pass + ... + >>> SomeClass.method = mocksignature(SomeClass.method) + >>> SomeClass.method.mock.return_value = None + >>> instance = SomeClass() + >>> instance.method() + Traceback (most recent call last): + ... + TypeError: <lambda>() takes at least 4 arguments (1 given) + >>> instance.method(1, 2, 3) + >>> instance.method.assert_called_with(instance, 1, 2, 3) + +When you use `mocksignature` on instance methods `self` isn't included (and we +can set the `return_value` etc directly): + +.. doctest:: + + >>> class SomeClass(object): + ... def method(self, a, b, c=None): + ... pass + ... + >>> instance = SomeClass() + >>> instance.method = mocksignature(instance.method) + >>> instance.method.return_value = None + >>> instance.method(1, 2, 3) + >>> instance.method.assert_called_with(1, 2, 3) + + +mocksignature with classes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When used with a class `mocksignature` copies the signature of the `__init__` +method. + +.. doctest:: + + >>> class Something(object): + ... def __init__(self, foo, bar): + ... pass + ... + >>> MockSomething = mocksignature(Something) + >>> instance = MockSomething(10, 9) + >>> assert instance is MockSomething.return_value + >>> MockSomething.assert_called_with(10, 9) + >>> MockSomething() + 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 with callable objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When used with a callable object `mocksignature` copies the signature of the +`__call__` method. + +.. doctest:: + + >>> class Something(object): + ... def __call__(self, spam, eggs): + ... pass + ... + >>> something = Something() + >>> mock_something = mocksignature(something) + >>> result = mock_something(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) + + +mocksignature argument to patch +------------------------------- + +`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. + +.. doctest:: + + >>> class SomeClass(object): + ... def method(self, a, b, c=None): + ... pass + ... + >>> @patch.object(SomeClass, 'method', mocksignature=True) + ... def test(mock_method): + ... instance = SomeClass() + ... mock_method.return_value = None + ... instance.method(1, 2) + ... mock_method.assert_called_with(instance, 1, 2, None) + ... + >>> test() |