Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | mock is a library for testing in Python. It allows you to replace parts of |
michael@0 | 2 | your system under test with mock objects and make assertions about how they |
michael@0 | 3 | have been used. |
michael@0 | 4 | |
michael@0 | 5 | mock is now part of the Python standard library, available as `unittest.mock < |
michael@0 | 6 | http://docs.python.org/py3k/library/unittest.mock.html#module-unittest.mock>`_ |
michael@0 | 7 | in Python 3.3 onwards. |
michael@0 | 8 | |
michael@0 | 9 | mock provides a core `MagicMock` class removing the need to create a host of |
michael@0 | 10 | stubs throughout your test suite. After performing an action, you can make |
michael@0 | 11 | assertions about which methods / attributes were used and arguments they were |
michael@0 | 12 | called with. You can also specify return values and set needed attributes in |
michael@0 | 13 | the normal way. |
michael@0 | 14 | |
michael@0 | 15 | mock is tested on Python versions 2.4-2.7 and Python 3. mock is also tested |
michael@0 | 16 | with the latest versions of Jython and pypy. |
michael@0 | 17 | |
michael@0 | 18 | The mock module also provides utility functions / objects to assist with |
michael@0 | 19 | testing, particularly monkey patching. |
michael@0 | 20 | |
michael@0 | 21 | * `PDF documentation for 1.0 beta 1 |
michael@0 | 22 | <http://www.voidspace.org.uk/downloads/mock-1.0.0.pdf>`_ |
michael@0 | 23 | * `mock on google code (repository and issue tracker) |
michael@0 | 24 | <http://code.google.com/p/mock/>`_ |
michael@0 | 25 | * `mock documentation |
michael@0 | 26 | <http://www.voidspace.org.uk/python/mock/>`_ |
michael@0 | 27 | * `mock on PyPI <http://pypi.python.org/pypi/mock/>`_ |
michael@0 | 28 | * `Mailing list (testing-in-python@lists.idyll.org) |
michael@0 | 29 | <http://lists.idyll.org/listinfo/testing-in-python>`_ |
michael@0 | 30 | |
michael@0 | 31 | Mock is very easy to use and is designed for use with |
michael@0 | 32 | `unittest <http://pypi.python.org/pypi/unittest2>`_. Mock is based on |
michael@0 | 33 | the 'action -> assertion' pattern instead of 'record -> replay' used by many |
michael@0 | 34 | mocking frameworks. See the `mock documentation`_ for full details. |
michael@0 | 35 | |
michael@0 | 36 | Mock objects create all attributes and methods as you access them and store |
michael@0 | 37 | details of how they have been used. You can configure them, to specify return |
michael@0 | 38 | values or limit what attributes are available, and then make assertions about |
michael@0 | 39 | how they have been used:: |
michael@0 | 40 | |
michael@0 | 41 | >>> from mock import Mock |
michael@0 | 42 | >>> real = ProductionClass() |
michael@0 | 43 | >>> real.method = Mock(return_value=3) |
michael@0 | 44 | >>> real.method(3, 4, 5, key='value') |
michael@0 | 45 | 3 |
michael@0 | 46 | >>> real.method.assert_called_with(3, 4, 5, key='value') |
michael@0 | 47 | |
michael@0 | 48 | `side_effect` allows you to perform side effects, return different values or |
michael@0 | 49 | raise an exception when a mock is called:: |
michael@0 | 50 | |
michael@0 | 51 | >>> mock = Mock(side_effect=KeyError('foo')) |
michael@0 | 52 | >>> mock() |
michael@0 | 53 | Traceback (most recent call last): |
michael@0 | 54 | ... |
michael@0 | 55 | KeyError: 'foo' |
michael@0 | 56 | >>> values = {'a': 1, 'b': 2, 'c': 3} |
michael@0 | 57 | >>> def side_effect(arg): |
michael@0 | 58 | ... return values[arg] |
michael@0 | 59 | ... |
michael@0 | 60 | >>> mock.side_effect = side_effect |
michael@0 | 61 | >>> mock('a'), mock('b'), mock('c') |
michael@0 | 62 | (3, 2, 1) |
michael@0 | 63 | >>> mock.side_effect = [5, 4, 3, 2, 1] |
michael@0 | 64 | >>> mock(), mock(), mock() |
michael@0 | 65 | (5, 4, 3) |
michael@0 | 66 | |
michael@0 | 67 | Mock has many other ways you can configure it and control its behaviour. For |
michael@0 | 68 | example the `spec` argument configures the mock to take its specification from |
michael@0 | 69 | another object. Attempting to access attributes or methods on the mock that |
michael@0 | 70 | don't exist on the spec will fail with an `AttributeError`. |
michael@0 | 71 | |
michael@0 | 72 | The `patch` decorator / context manager makes it easy to mock classes or |
michael@0 | 73 | objects in a module under test. The object you specify will be replaced with a |
michael@0 | 74 | mock (or other object) during the test and restored when the test ends:: |
michael@0 | 75 | |
michael@0 | 76 | >>> from mock import patch |
michael@0 | 77 | >>> @patch('test_module.ClassName1') |
michael@0 | 78 | ... @patch('test_module.ClassName2') |
michael@0 | 79 | ... def test(MockClass2, MockClass1): |
michael@0 | 80 | ... test_module.ClassName1() |
michael@0 | 81 | ... test_module.ClassName2() |
michael@0 | 82 | |
michael@0 | 83 | ... assert MockClass1.called |
michael@0 | 84 | ... assert MockClass2.called |
michael@0 | 85 | ... |
michael@0 | 86 | >>> test() |
michael@0 | 87 | |
michael@0 | 88 | .. note:: |
michael@0 | 89 | |
michael@0 | 90 | When you nest patch decorators the mocks are passed in to the decorated |
michael@0 | 91 | function in the same order they applied (the normal *python* order that |
michael@0 | 92 | decorators are applied). This means from the bottom up, so in the example |
michael@0 | 93 | above the mock for `test_module.ClassName2` is passed in first. |
michael@0 | 94 | |
michael@0 | 95 | With `patch` it matters that you patch objects in the namespace where they |
michael@0 | 96 | are looked up. This is normally straightforward, but for a quick guide |
michael@0 | 97 | read `where to patch |
michael@0 | 98 | <http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch>`_. |
michael@0 | 99 | |
michael@0 | 100 | As well as a decorator `patch` can be used as a context manager in a with |
michael@0 | 101 | statement:: |
michael@0 | 102 | |
michael@0 | 103 | >>> with patch.object(ProductionClass, 'method') as mock_method: |
michael@0 | 104 | ... mock_method.return_value = None |
michael@0 | 105 | ... real = ProductionClass() |
michael@0 | 106 | ... real.method(1, 2, 3) |
michael@0 | 107 | ... |
michael@0 | 108 | >>> mock_method.assert_called_once_with(1, 2, 3) |
michael@0 | 109 | |
michael@0 | 110 | There is also `patch.dict` for setting values in a dictionary just during the |
michael@0 | 111 | scope of a test and restoring the dictionary to its original state when the |
michael@0 | 112 | test ends:: |
michael@0 | 113 | |
michael@0 | 114 | >>> foo = {'key': 'value'} |
michael@0 | 115 | >>> original = foo.copy() |
michael@0 | 116 | >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): |
michael@0 | 117 | ... assert foo == {'newkey': 'newvalue'} |
michael@0 | 118 | ... |
michael@0 | 119 | >>> assert foo == original |
michael@0 | 120 | |
michael@0 | 121 | Mock supports the mocking of Python magic methods. The easiest way of |
michael@0 | 122 | using magic methods is with the `MagicMock` class. It allows you to do |
michael@0 | 123 | things like:: |
michael@0 | 124 | |
michael@0 | 125 | >>> from mock import MagicMock |
michael@0 | 126 | >>> mock = MagicMock() |
michael@0 | 127 | >>> mock.__str__.return_value = 'foobarbaz' |
michael@0 | 128 | >>> str(mock) |
michael@0 | 129 | 'foobarbaz' |
michael@0 | 130 | >>> mock.__str__.assert_called_once_with() |
michael@0 | 131 | |
michael@0 | 132 | Mock allows you to assign functions (or other Mock instances) to magic methods |
michael@0 | 133 | and they will be called appropriately. The MagicMock class is just a Mock |
michael@0 | 134 | variant that has all of the magic methods pre-created for you (well - all the |
michael@0 | 135 | useful ones anyway). |
michael@0 | 136 | |
michael@0 | 137 | The following is an example of using magic methods with the ordinary Mock |
michael@0 | 138 | class:: |
michael@0 | 139 | |
michael@0 | 140 | >>> from mock import Mock |
michael@0 | 141 | >>> mock = Mock() |
michael@0 | 142 | >>> mock.__str__ = Mock(return_value = 'wheeeeee') |
michael@0 | 143 | >>> str(mock) |
michael@0 | 144 | 'wheeeeee' |
michael@0 | 145 | |
michael@0 | 146 | For ensuring that the mock objects your tests use have the same api as the |
michael@0 | 147 | objects they are replacing, you can use "auto-speccing". Auto-speccing can |
michael@0 | 148 | be done through the `autospec` argument to patch, or the `create_autospec` |
michael@0 | 149 | function. Auto-speccing creates mock objects that have the same attributes |
michael@0 | 150 | and methods as the objects they are replacing, and any functions and methods |
michael@0 | 151 | (including constructors) have the same call signature as the real object. |
michael@0 | 152 | |
michael@0 | 153 | This ensures that your mocks will fail in the same way as your production |
michael@0 | 154 | code if they are used incorrectly:: |
michael@0 | 155 | |
michael@0 | 156 | >>> from mock import create_autospec |
michael@0 | 157 | >>> def function(a, b, c): |
michael@0 | 158 | ... pass |
michael@0 | 159 | ... |
michael@0 | 160 | >>> mock_function = create_autospec(function, return_value='fishy') |
michael@0 | 161 | >>> mock_function(1, 2, 3) |
michael@0 | 162 | 'fishy' |
michael@0 | 163 | >>> mock_function.assert_called_once_with(1, 2, 3) |
michael@0 | 164 | >>> mock_function('wrong arguments') |
michael@0 | 165 | Traceback (most recent call last): |
michael@0 | 166 | ... |
michael@0 | 167 | TypeError: <lambda>() takes exactly 3 arguments (1 given) |
michael@0 | 168 | |
michael@0 | 169 | `create_autospec` can also be used on classes, where it copies the signature of |
michael@0 | 170 | the `__init__` method, and on callable objects where it copies the signature of |
michael@0 | 171 | the `__call__` method. |
michael@0 | 172 | |
michael@0 | 173 | The distribution contains tests and documentation. The tests require |
michael@0 | 174 | `unittest2 <http://pypi.python.org/pypi/unittest2>`_ to run. |
michael@0 | 175 | |
michael@0 | 176 | Docs from the in-development version of `mock` can be found at |
michael@0 | 177 | `mock.readthedocs.org <http://mock.readthedocs.org>`_. |