michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: mocksignature — Mock 0.8.1alpha1 documentation michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0: michael@0:
michael@0:

mocksignature

michael@0:
michael@0:

Note

michael@0:

Autospeccing, added in mock 0.8, is a more advanced version of michael@0: mocksignature and can be used for many of the same use cases.

michael@0:
michael@0:

A problem with using mock objects to replace real objects in your tests is that michael@0: Mock can be too flexible. Your code can treat the mock objects in michael@0: any way and you have to manually check that they were called correctly. If your michael@0: code calls functions or methods with the wrong number of arguments then mocks michael@0: don’t complain.

michael@0:

The solution to this is mocksignature, which creates functions with the michael@0: same signature as the original, but delegating to a mock. You can interrogate michael@0: the mock in the usual way to check it has been called with the right michael@0: arguments, but if it is called with the wrong number of arguments it will michael@0: raise a TypeError in the same way your production code would.

michael@0:

Another advantage is that your mocked objects are real functions, which can michael@0: be useful when your code uses michael@0: inspect or depends on michael@0: functions being function objects.

michael@0:
michael@0:
michael@0: mocksignature(func, mock=None, skipfirst=False)
michael@0:

Create a new function with the same signature as func that delegates michael@0: to mock. If skipfirst is True the first argument is skipped, useful michael@0: for methods where self needs to be omitted from the new function.

michael@0:

If you don’t pass in a mock then one will be created for you.

michael@0:

Functions returned by mocksignature have many of the same attributes michael@0: and assert methods as a mock object.

michael@0:

The mock is set as the mock attribute of the returned function for easy michael@0: access.

michael@0:

mocksignature can also be used with classes. It copies the signature of michael@0: the __init__ method.

michael@0:

When used with callable objects (instances) it copies the signature of the michael@0: __call__ method.

michael@0:
michael@0: michael@0:

mocksignature will work out if it is mocking the signature of a method on michael@0: an instance or a method on a class and do the “right thing” with the self michael@0: argument in both cases.

michael@0:

Because of a limitation in the way that arguments are collected by functions michael@0: created by mocksignature they are always passed as positional arguments michael@0: (including defaults) and not keyword arguments.

michael@0:
michael@0:

mocksignature api

michael@0:

Although the objects returned by mocksignature api are real function objects, michael@0: they have much of the same api as the Mock class. This includes the michael@0: assert methods:

michael@0:
>>> def func(a, b, c):
michael@0: ...     pass
michael@0: ...
michael@0: >>> func2 = mocksignature(func)
michael@0: >>> func2.called
michael@0: False
michael@0: >>> func2.return_value = 3
michael@0: >>> func2(1, 2, 3)
michael@0: 3
michael@0: >>> func2.called
michael@0: True
michael@0: >>> func2.assert_called_once_with(1, 2, 3)
michael@0: >>> func2.assert_called_with(1, 2, 4)
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: AssertionError: Expected call: mock(1, 2, 4)
michael@0: Actual call: mock(1, 2, 3)
michael@0: >>> func2.call_count
michael@0: 1
michael@0: >>> func2.side_effect = IndexError
michael@0: >>> func2(4, 5, 6)
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: IndexError
michael@0: 
michael@0:
michael@0:

The mock object that is being delegated to is available as the mock attribute michael@0: of the function created by mocksignature.

michael@0:
>>> func2.mock.mock_calls
michael@0: [call(1, 2, 3), call(4, 5, 6)]
michael@0: 
michael@0:
michael@0:

The methods and attributes available on functions returned by mocksignature michael@0: are:

michael@0:
michael@0:
michael@0:
michael@0:
michael@0:

Example use

michael@0:
michael@0:

Basic use

michael@0:
>>> def function(a, b, c=None):
michael@0: ...     pass
michael@0: ...
michael@0: >>> mock = Mock()
michael@0: >>> function = mocksignature(function, mock)
michael@0: >>> function()
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: TypeError: <lambda>() takes at least 2 arguments (0 given)
michael@0: >>> function.return_value = 'some value'
michael@0: >>> function(1, 2, 'foo')
michael@0: 'some value'
michael@0: >>> function.assert_called_with(1, 2, 'foo')
michael@0: 
michael@0:
michael@0:
michael@0:
michael@0:

Keyword arguments

michael@0:

Note that arguments to functions created by mocksignature are always passed michael@0: in to the underlying mock by position even when called with keywords:

michael@0:
>>> def function(a, b, c=None):
michael@0: ...     pass
michael@0: ...
michael@0: >>> function = mocksignature(function)
michael@0: >>> function.return_value = None
michael@0: >>> function(1, 2)
michael@0: >>> function.assert_called_with(1, 2, None)
michael@0: 
michael@0:
michael@0:
michael@0:
michael@0:

Mocking methods and self

michael@0:

When you use mocksignature to replace a method on a class then self michael@0: will be included in the method signature - and you will need to include michael@0: the instance when you do your asserts.

michael@0:

As a curious factor of the way Python (2) wraps methods fetched from a class, michael@0: we can get the return_value from a function set on a class, but we can’t michael@0: set it. We have to do this through the exposed mock attribute instead:

michael@0:
>>> class SomeClass(object):
michael@0: ...     def method(self, a, b, c=None):
michael@0: ...         pass
michael@0: ...
michael@0: >>> SomeClass.method = mocksignature(SomeClass.method)
michael@0: >>> SomeClass.method.mock.return_value = None
michael@0: >>> instance = SomeClass()
michael@0: >>> instance.method()
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: TypeError: <lambda>() takes at least 4 arguments (1 given)
michael@0: >>> instance.method(1, 2, 3)
michael@0: >>> instance.method.assert_called_with(instance, 1, 2, 3)
michael@0: 
michael@0:
michael@0:

When you use mocksignature on instance methods self isn’t included (and we michael@0: can set the return_value etc directly):

michael@0:
>>> class SomeClass(object):
michael@0: ...     def method(self, a, b, c=None):
michael@0: ...         pass
michael@0: ...
michael@0: >>> instance = SomeClass()
michael@0: >>> instance.method = mocksignature(instance.method)
michael@0: >>> instance.method.return_value = None
michael@0: >>> instance.method(1, 2, 3)
michael@0: >>> instance.method.assert_called_with(1, 2, 3)
michael@0: 
michael@0:
michael@0:
michael@0:
michael@0:

mocksignature with classes

michael@0:

When used with a class mocksignature copies the signature of the __init__ michael@0: method.

michael@0:
>>> class Something(object):
michael@0: ...     def __init__(self, foo, bar):
michael@0: ...         pass
michael@0: ...
michael@0: >>> MockSomething = mocksignature(Something)
michael@0: >>> instance = MockSomething(10, 9)
michael@0: >>> assert instance is MockSomething.return_value
michael@0: >>> MockSomething.assert_called_with(10, 9)
michael@0: >>> MockSomething()
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: TypeError: <lambda>() takes at least 2 arguments (0 given)
michael@0: 
michael@0:
michael@0:

Because the object returned by mocksignature is a function rather than a michael@0: Mock you lose the other capabilities of Mock, like dynamic attribute michael@0: creation.

michael@0:
michael@0:
michael@0:

mocksignature with callable objects

michael@0:

When used with a callable object mocksignature copies the signature of the michael@0: __call__ method.

michael@0:
>>> class Something(object):
michael@0: ...     def __call__(self, spam, eggs):
michael@0: ...         pass
michael@0: ...
michael@0: >>> something = Something()
michael@0: >>> mock_something = mocksignature(something)
michael@0: >>> result = mock_something(10, 9)
michael@0: >>> mock_something.assert_called_with(10, 9)
michael@0: >>> mock_something()
michael@0: Traceback (most recent call last):
michael@0:   ...
michael@0: TypeError: <lambda>() takes at least 2 arguments (0 given)
michael@0: 
michael@0:
michael@0:
michael@0:
michael@0:
michael@0:

mocksignature argument to patch

michael@0:

mocksignature is available as a keyword argument to patch() or michael@0: patch.object(). It can be used with functions / methods / classes and michael@0: callable objects.

michael@0:
>>> class SomeClass(object):
michael@0: ...     def method(self, a, b, c=None):
michael@0: ...         pass
michael@0: ...
michael@0: >>> @patch.object(SomeClass, 'method', mocksignature=True)
michael@0: ... def test(mock_method):
michael@0: ...     instance = SomeClass()
michael@0: ...     mock_method.return_value = None
michael@0: ...     instance.method(1, 2)
michael@0: ...     mock_method.assert_called_with(instance, 1, 2, None)
michael@0: ...
michael@0: >>> test()
michael@0: 
michael@0:
michael@0:
michael@0:
michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0:
michael@0:

Table Of Contents

michael@0: michael@0: michael@0:

Previous topic

michael@0:

Mocking Magic Methods

michael@0:

Next topic

michael@0:

Getting Started with Mock

michael@0:

This Page

michael@0: michael@0: michael@0: michael@0:
michael@0:
michael@0:
michael@0:
michael@0: michael@0: michael@0: michael@0: