unittest.mock.md
1> **Источник:** https://python-all.ru/3.4/library/unittest.mock.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 26.4. [`unittest.mock`](https://python-all.ru/3.4/library/unittest.mock.html#module-unittest.mock) – библиотека mock-объектов89Новое в версии 3.3.1011[`unittest.mock`](https://python-all.ru/3.4/library/unittest.mock.html#module-unittest.mock) – библиотека для тестирования в Python. С её помощью можно заменять части тестируемой системы mock-объектами и проверять, как они использовались.1213[`unittest.mock`](https://python-all.ru/3.4/library/unittest.mock.html#module-unittest.mock) предоставляет основной класс [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock), устраняя необходимость создавать множество заглушек в тестовом наборе. После выполнения действия можно проверять, какие методы и атрибуты использовались и с какими аргументами они вызывались. Также можно обычным способом задавать возвращаемые значения и устанавливать нужные атрибуты.1415Кроме того, mock предоставляет декоратор [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), который подменяет атрибуты модулей и классов в пределах теста, а также [`sentinel`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.sentinel) для создания уникальных объектов. Примеры использования [https://python-all.ru/3.4/library/unittest.mock.html#quick-guide](https://python-all.ru/3.4/library/unittest.mock.html#quick-guide), и см. в кратком руководстве.1617Mock очень прост в использовании и предназначен для работы с [`unittest`](https://python-all.ru/3.4/library/unittest.html#module-unittest). Он основан на шаблоне «действие → проверка», а не «запись → воспроизведение», который применяется во многих других mocking-фреймворках.1819Для более старых версий Python существует обратный порт [`unittest.mock`](https://python-all.ru/3.4/library/unittest.mock.html#module-unittest.mock), доступный как [mock на PyPI](https://python-all.ru/3.4/library/unittest.mock.html).2021**Исходный код:** [Lib/unittest/mock.py](https://python-all.ru/src/3.4/Lib/unittest/mock.py)2223## 26.4.1. Краткое руководство2425Объекты [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) и [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) создают все атрибуты и методы по мере обращения к ним и запоминают подробности их использования. Можно настраивать их, задавая возвращаемые значения или ограничивая доступные атрибуты, а затем проверять, как они использовались:2627```python28>>> from unittest.mock import MagicMock29>>> thing = ProductionClass()30>>> thing.method = MagicMock(return_value=3)31>>> thing.method(3, 4, 5, key='value')32333>>> thing.method.assert_called_with(3, 4, 5, key='value')34```3536`side_effect` позволяет выполнять побочные действия, в том числе вызывать исключение при вызове mock-объекта:3738```python39>>> mock = Mock(side_effect=KeyError('foo'))40>>> mock()41Traceback (most recent call last):42 ...43KeyError: 'foo'44```4546```python47>>> values = {'a': 1, 'b': 2, 'c': 3}48>>> def side_effect(arg):49... return values[arg]50...51>>> mock.side_effect = side_effect52>>> mock('a'), mock('b'), mock('c')53(1, 2, 3)54>>> mock.side_effect = [5, 4, 3, 2, 1]55>>> mock(), mock(), mock()56(5, 4, 3)57```5859У Mock есть много других способов настройки и управления поведением. Например, аргумент *spec* задаёт mock-объекту спецификацию, взятую из другого объекта. Попытка обратиться к атрибутам или методам, которых нет в спецификации, завершится ошибкой [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).6061Декоратор/менеджер контекста [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) упрощает подмену классов или объектов в тестируемом модуле. Указанный объект заменяется mock-объектом (или другим объектом) на время теста и восстанавливается после его завершения:6263```python64>>> from unittest.mock import patch65>>> @patch('module.ClassName2')66... @patch('module.ClassName1')67... def test(MockClass1, MockClass2):68... module.ClassName1()69... module.ClassName2()70... assert MockClass1 is module.ClassName171... assert MockClass2 is module.ClassName272... assert MockClass1.called73... assert MockClass2.called74...75>>> test()76```7778> **Примечание**79>80> When you nest patch decorators the mocks are passed in to the decorated function in the same order they applied (the normal *python* order that decorators are applied). This means from the bottom up, so in the example above the mock for `module.ClassName1` is passed in first.81>82> При использовании [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) важно подменять объекты в том пространстве имён, где они ищутся. Обычно это просто, но для быстрого ознакомления прочитайте [*где подменять*](https://python-all.ru/3.4/library/unittest.mock.html#where-to-patch).8384Помимо декоратора, [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) можно использовать как менеджер контекста в операторе with:8586```python87>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:88... thing = ProductionClass()89... thing.method(1, 2, 3)90...91>>> mock_method.assert_called_once_with(1, 2, 3)92```9394Существует также [`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) для установки значений в словаре только в пределах области видимости с последующим восстановлением исходного состояния словаря после завершения теста:9596```python97>>> foo = {'key': 'value'}98>>> original = foo.copy()99>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):100... assert foo == {'newkey': 'newvalue'}101...102>>> assert foo == original103```104105Mock поддерживает имитацию [*магических методов*](https://python-all.ru/3.4/library/unittest.mock.html#magic-methods) Python. Самый простой способ использования магических методов – класс [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock). Он позволяет делать, например, следующее:106107```python108>>> mock = MagicMock()109>>> mock.__str__.return_value = 'foobarbaz'110>>> str(mock)111'foobarbaz'112>>> mock.__str__.assert_called_with()113```114115Mock позволяет назначать функции (или другие экземпляры Mock) магическим методам, и они будут вызываться соответствующим образом. Класс [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) – это просто разновидность Mock, в которой все магические методы уже предсозданы (по крайней мере, все полезные).116117Далее приведён пример использования магических методов с обычным классом Mock:118119```python120>>> mock = Mock()121>>> mock.__str__ = Mock(return_value='wheeeeee')122>>> str(mock)123'wheeeeee'124```125126Чтобы mock-объекты в тестах имели тот же API, что и заменяемые объекты, можно использовать [*автоспецификацию*](https://python-all.ru/3.4/library/unittest.mock.html#auto-speccing). Автоспецификацию можно задать через аргумент *autospec* у patch или с помощью функции [`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec). Автоспецификация создаёт mock-объекты, имеющие те же атрибуты и методы, что и заменяемые объекты, а любые функции и методы (включая конструкторы) имеют ту же сигнатуру вызова, что и реальный объект.127128Благодаря этому заглушки будут вести себя так же, как рабочий код, если их использовать неправильно:129130```python131>>> from unittest.mock import create_autospec132>>> def function(a, b, c):133... pass134...135>>> mock_function = create_autospec(function, return_value='fishy')136>>> mock_function(1, 2, 3)137'fishy'138>>> mock_function.assert_called_once_with(1, 2, 3)139>>> mock_function('wrong arguments')140Traceback (most recent call last):141 ...142TypeError: <lambda>() takes exactly 3 arguments (1 given)143```144145[`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) также можно применять к классам (копирует сигнатуру метода `__init__`) и к вызываемым объектам (копирует сигнатуру метода `__call__`).146147## 26.4.2. Класс Mock148149[`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) – это гибкий mock-объект, предназначенный для замены заглушек и тестовых двойников в коде. Mock-объекты вызываемы и создают атрибуты как новые mock-объекты при обращении к ним [\[1\]](https://python-all.ru/3.4/library/unittest.mock.html#id3). Обращение к одному и тому же атрибуту всегда возвращает один и тот же mock. Mock-объекты записывают, как они используются, позволяя проверять, что код с ними сделал.150151[`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) – это подкласс [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) со всеми магическими методами, предсозданными и готовыми к использованию. Существуют также невызываемые варианты, полезные при имитации объектов, которые не являются вызываемыми: [`NonCallableMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.NonCallableMock) и [`NonCallableMagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.NonCallableMagicMock)152153Декораторы [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) упрощают временную замену классов в определённом модуле на объект [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock). По умолчанию [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) создаёт [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock). Можно указать альтернативный класс [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) с помощью аргумента *new\_callable* у [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch).154155#### `class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs)`156157Создаёт новый объект [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock). [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) принимает несколько необязательных аргументов, задающих поведение объекта Mock:158159- *spec*: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods). Accessing any attribute not in this list will raise an [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).160161 Если *spec* – объект (а не список строк), то [`__class__`](https://python-all.ru/3.4/library/stdtypes.html#instance.__class__) возвращает класс объекта спецификации. Это позволяет mock-объектам проходить проверки [`isinstance()`](https://python-all.ru/3.4/library/functions.html#isinstance).162- *spec\_set*: более строгий вариант *spec*. Если он используется, попытка *установить* или получить атрибут mock-объекта, которого нет у объекта, переданного как *spec\_set*, вызовет [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).163- *side\_effect*: функция, вызываемая при каждом вызове Mock. См. атрибут [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect). Полезен для генерации исключений или динамического изменения возвращаемых значений. Функция вызывается с теми же аргументами, что и mock, и если она не возвращает [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT), то возвращаемое значение этой функции используется как возвращаемое значение.164165 Альтернативно *side\_effect* может быть классом исключения или экземпляром. В этом случае исключение будет возбуждено при вызове заглушки.166167 Если *side\_effect* является итерируемым, то каждый вызов заглушки будет возвращать следующее значение из итерируемого.168169 *side\_effect* можно очистить, присвоив ему значение `None`.170- *return\_value*: значение, возвращаемое при вызове mock-объекта. По умолчанию это новый Mock (создаётся при первом обращении). См. атрибут [`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value).171- *wraps*: элемент, который оборачивает mock-объект. Если *wraps* не равен None, то вызов Mock передаст вызов обёрнутому объекту (возвращая реальный результат). Обращение к атрибуту mock'а вернёт Mock-объект, оборачивающий соответствующий атрибут обёрнутого объекта (поэтому попытка обратиться к несуществующему атрибуту вызовет [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError)).172173 Если для заглушки явно задан *return\_value*, то вызовы не передаются обёрнутому объекту, а возвращается значение *return\_value*.174- *name*: если у заглушки есть имя, оно будет использоваться в repr заглушки. Это может быть полезно для отладки. Имя распространяется на дочерние заглушки.175176Mock-объекты также можно вызывать с произвольными именованными аргументами. Они будут использованы для установки атрибутов mock'а после его создания. Подробнее см. метод [`configure_mock()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.configure_mock).177178#### `assert_called_with(*args, **kwargs)`179180Этот метод – удобный способ проверить, что вызовы сделаны определённым образом:181182```python183>>> mock = Mock()184>>> mock.method(1, 2, 3, test='wow')185<Mock name='mock.method()' id='...'>186>>> mock.method.assert_called_with(1, 2, 3, test='wow')187```188189#### `assert_called_once_with(*args, **kwargs)`190191Утверждает, что mock был вызван ровно один раз и с указанными аргументами.192193```python194>>> mock = Mock(return_value=None)195>>> mock('foo', bar='baz')196>>> mock.assert_called_once_with('foo', bar='baz')197>>> mock('foo', bar='baz')198>>> mock.assert_called_once_with('foo', bar='baz')199Traceback (most recent call last):200 ...201AssertionError: Expected 'mock' to be called once. Called 2 times.202```203204#### `assert_any_call(*args, **kwargs)`205206Утверждает, что заглушка вызывалась с указанными аргументами.207208Утверждение проходит, если mock *когда-либо* был вызван, в отличие от [`assert_called_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_with) и [`assert_called_once_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with), которые проходят только в том случае, если вызов был последним.209210```python211>>> mock = Mock(return_value=None)212>>> mock(1, 2, arg='thing')213>>> mock('some', 'thing', 'else')214>>> mock.assert_any_call(1, 2, arg='thing')215```216217#### `assert_has_calls(calls, any_order=False)`218219Утверждает, что mock был вызван с указанными вызовами. Проверяется список [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls).220221Если *any\_order* равно false (значение по умолчанию), то вызовы должны быть последовательными. Допускаются дополнительные вызовы до или после указанных вызовов.222223Если *any\_order* равен true, то вызовы могут быть в любом порядке, но все они должны присутствовать в [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls).224225```python226>>> mock = Mock(return_value=None)227>>> mock(1)228>>> mock(2)229>>> mock(3)230>>> mock(4)231>>> calls = [call(2), call(3)]232>>> mock.assert_has_calls(calls)233>>> calls = [call(4), call(2), call(3)]234>>> mock.assert_has_calls(calls, any_order=True)235```236237#### `reset_mock()`238239Метод reset\_mock сбрасывает все атрибуты вызовов у макета:240241```python242>>> mock = Mock(return_value=None)243>>> mock('hello')244>>> mock.called245True246>>> mock.reset_mock()247>>> mock.called248False249```250251Это может быть полезно, когда нужно выполнить серию утверждений, использующих один и тот же объект. Обратите внимание, что [`reset_mock()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.reset_mock) *не* очищает возвращаемое значение, [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect) или любые дочерние атрибуты, установленные с помощью обычного присваивания. Дочерние mock'и и mock возвращаемого значения (если есть) также сбрасываются.252253#### `mock_add_spec(spec, spec_set=False)`254255Добавляет спецификацию к макету. *spec* может быть объектом или списком строк. Только атрибуты, указанные в *spec*, можно получить как атрибуты макета.256257Если *spec\_set* имеет значение true, то можно устанавливать только атрибуты, указанные в спецификации.258259#### `attach_mock(mock, attribute)`260261Присоединяет mock в качестве атрибута данного mock'а, заменяя его имя и родителя. Вызовы присоединённого mock'а будут записываться в атрибутах [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) данного объекта.262263#### `configure_mock(**kwargs)`264265Устанавливает атрибуты макета через именованные аргументы.266267Атрибуты, возвращаемые значения и побочные эффекты могут быть установлены на дочерних макетах с помощью стандартной точечной нотации и распаковки словаря в вызове метода:268269```python270>>> mock = Mock()271>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}272>>> mock.configure_mock(**attrs)273>>> mock.method()2743275>>> mock.other()276Traceback (most recent call last):277 ...278KeyError279```280281То же самое можно сделать в вызове конструктора макетов:282283```python284>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}285>>> mock = Mock(some_attribute='eggs', **attrs)286>>> mock.some_attribute287'eggs'288>>> mock.method()2893290>>> mock.other()291Traceback (most recent call last):292 ...293KeyError294```295296[`configure_mock()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.configure_mock) существует для упрощения настройки после создания mock'а.297298#### `__dir__()`299300Объекты [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) ограничивают результаты `dir(some_mock)` полезными результатами. Для mock'ов с *spec* это включает все разрешённые атрибуты для mock'а.301302См. [`FILTER_DIR`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.FILTER_DIR), чтобы узнать, что делает эта фильтрация и как её отключить.303304#### `_get_child_mock(**kw)`305306Создаёт дочерние макеты для атрибутов и возвращаемого значения. По умолчанию дочерние макеты будут того же типа, что и родительский. Подклассы Mock могут переопределить это для настройки способа создания дочерних макетов.307308Для невызываемых макетов будет использоваться вызываемый вариант (а не пользовательский подкласс).309310#### `called`311312Логическое значение, указывающее, был ли вызван mock-объект:313314```python315>>> mock = Mock(return_value=None)316>>> mock.called317False318>>> mock()319>>> mock.called320True321```322323#### `call_count`324325Целое число, показывающее, сколько раз был вызван mock-объект:326327```python328>>> mock = Mock(return_value=None)329>>> mock.call_count3300331>>> mock()332>>> mock()333>>> mock.call_count3342335```336337#### `return_value`338339Установите это, чтобы настроить значение, возвращаемое при вызове mock:340341```python342>>> mock = Mock()343>>> mock.return_value = 'fish'344>>> mock()345'fish'346```347348Значение по умолчанию – это mock-объект, и его можно настроить обычным способом:349350```python351>>> mock = Mock()352>>> mock.return_value.attribute = sentinel.Attribute353>>> mock.return_value()354<Mock name='mock()()' id='...'>355>>> mock.return_value.assert_called_with()356```357358[`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value) также можно установить в конструкторе:359360```python361>>> mock = Mock(return_value=3)362>>> mock.return_value3633364>>> mock()3653366```367368#### `side_effect`369370Это может быть функция, вызываемая при вызове mock-объекта, итерируемый объект или исключение (класс или экземпляр), которое должно быть возбуждено.371372Если передать функцию, она будет вызвана с теми же аргументами, что и mock, и если функция не вернёт синглтон [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT), то вызов mock'а вернёт то, что вернула функция. Если функция возвращает [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT), то mock вернёт своё обычное значение (из [`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value)).373374Если передать итерируемый объект, он используется для получения итератора, который должен возвращать значение при каждом вызове. Это значение может быть либо экземпляром исключения, которое будет возбуждено, либо значением, возвращаемым при вызове mock'а ([`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT) обрабатывается так же, как в случае с функцией).375376Пример mock-объекта, возбуждающего исключение (для проверки обработки исключений API):377378```python379>>> mock = Mock()380>>> mock.side_effect = Exception('Boom!')381>>> mock()382Traceback (most recent call last):383 ...384Exception: Boom!385```386387Использование [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect) для возврата последовательности значений:388389```python390>>> mock = Mock()391>>> mock.side_effect = [3, 2, 1]392>>> mock(), mock(), mock()393(3, 2, 1)394```395396Использование вызываемого объекта:397398```python399>>> mock = Mock(return_value=3)400>>> def side_effect(*args, **kwargs):401... return DEFAULT402...403>>> mock.side_effect = side_effect404>>> mock()4053406```407408[`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect) можно установить в конструкторе. Вот пример, который добавляет единицу к значению, с которым вызывается mock, и возвращает его:409410```python411>>> side_effect = lambda value: value + 1412>>> mock = Mock(side_effect=side_effect)413>>> mock(3)4144415>>> mock(-8)416-7417```418419Установка [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect) в `None` очищает его:420421```python422>>> m = Mock(side_effect=KeyError, return_value=3)423>>> m()424Traceback (most recent call last):425 ...426KeyError427>>> m.side_effect = None428>>> m()4293430```431432#### `call_args`433434Это либо `None` (если макет не вызывался), либо аргументы, с которыми макет был вызван в последний раз. Они представлены в виде кортежа: первый элемент – позиционные аргументы, переданные макету (или пустой кортеж), второй элемент – именованные аргументы (или пустой словарь).435436```python437>>> mock = Mock(return_value=None)438>>> print(mock.call_args)439None440>>> mock()441>>> mock.call_args442call()443>>> mock.call_args == ()444True445>>> mock(3, 4)446>>> mock.call_args447call(3, 4)448>>> mock.call_args == ((3, 4),)449True450>>> mock(3, 4, 5, key='fish', next='w00t!')451>>> mock.call_args452call(3, 4, 5, key='fish', next='w00t!')453```454455[`call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args), а также элементы списков [`call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list), [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) являются объектами [`call`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call). Это кортежи, поэтому их можно распаковать для получения отдельных аргументов и составления более сложных утверждений. См. [*calls as tuples*](https://python-all.ru/3.4/library/unittest.mock.html#calls-as-tuples).456457#### `call_args_list`458459Это последовательный список всех вызовов, сделанных к объекту-макету (поэтому длина списка равна количеству вызовов). До первого вызова это пустой список. Объект [`call`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call) можно использовать для удобного построения списков вызовов для сравнения с [`call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list).460461```python462>>> mock = Mock(return_value=None)463>>> mock()464>>> mock(3, 4)465>>> mock(key='fish', next='w00t!')466>>> mock.call_args_list467[call(), call(3, 4), call(key='fish', next='w00t!')]468>>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)]469>>> mock.call_args_list == expected470True471```472473Элементы [`call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list) – это объекты [`call`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [*calls as tuples*](https://python-all.ru/3.4/library/unittest.mock.html#calls-as-tuples).474475#### `method_calls`476477Помимо отслеживания собственных вызовов, mock-объекты также отслеживают вызовы методов и атрибутов, а также *их* методов и атрибутов:478479```python480>>> mock = Mock()481>>> mock.method()482<Mock name='mock.method()' id='...'>483>>> mock.property.method.attribute()484<Mock name='mock.property.method.attribute()' id='...'>485>>> mock.method_calls486[call.method(), call.property.method.attribute()]487```488489Элементы [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls) – это объекты [`call`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [*calls as tuples*](https://python-all.ru/3.4/library/unittest.mock.html#calls-as-tuples).490491#### `mock_calls`492493[`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) записывает *все* вызовы объекта-макета, его методов, магических методов *и* макетов возвращаемых значений.494495```python496>>> mock = MagicMock()497>>> result = mock(1, 2, 3)498>>> mock.first(a=3)499<MagicMock name='mock.first()' id='...'>500>>> mock.second()501<MagicMock name='mock.second()' id='...'>502>>> int(mock)5031504>>> result(1)505<MagicMock name='mock()()' id='...'>506>>> expected = [call(1, 2, 3), call.first(a=3), call.second(),507... call.__int__(), call()(1)]508>>> mock.mock_calls == expected509True510```511512Элементы [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) – это объекты [`call`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [*calls as tuples*](https://python-all.ru/3.4/library/unittest.mock.html#calls-as-tuples).513514#### `__class__`515516Обычно атрибут [`__class__`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.__class__) объекта возвращает его тип. Для объекта-макета с `spec` атрибут `__class__` возвращает класс спецификации. Это позволяет объектам-макетам проходить проверки [`isinstance()`](https://python-all.ru/3.4/library/functions.html#isinstance) на объект, который они заменяют или выдают себя за него:517518```python519>>> mock = Mock(spec=3)520>>> isinstance(mock, int)521True522```523524Атрибуту [`__class__`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.__class__) можно присвоить значение, что позволяет макету проходить проверку [`isinstance()`](https://python-all.ru/3.4/library/functions.html#isinstance) без принудительного использования spec:525526```python527>>> mock = Mock()528>>> mock.__class__ = dict529>>> isinstance(mock, dict)530True531```532533#### `class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, **kwargs)`534535Невызываемая версия [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock). Параметры конструктора имеют тот же смысл, что и у [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock), за исключением *return\_value* и *side\_effect*, которые не имеют значения для невызываемого макета.536537Объекты-макеты, использующие класс или экземпляр в качестве `spec` или `spec_set`, способны проходить проверки [`isinstance()`](https://python-all.ru/3.4/library/functions.html#isinstance):538539```python540>>> mock = Mock(spec=SomeClass)541>>> isinstance(mock, SomeClass)542True543>>> mock = Mock(spec_set=SomeClass())544>>> isinstance(mock, SomeClass)545True546```547548Классы [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) поддерживают имитацию магических методов. Подробнее см. [*магические методы*](https://python-all.ru/3.4/library/unittest.mock.html#magic-methods).549550Классы макетов и декораторы [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) принимают произвольные именованные аргументы для настройки. Для декораторов [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) эти именованные аргументы передаются конструктору создаваемого макета. Именованные аргументы служат для настройки атрибутов макета:551552```python553>>> m = MagicMock(attribute=3, other='fish')554>>> m.attribute5553556>>> m.other557'fish'558```559560Возвращаемое значение и побочный эффект дочерних mock-объектов можно установить таким же образом, используя точечную нотацию. Поскольку точечные имена нельзя использовать непосредственно в вызове, необходимо создать словарь и распаковать его с помощью `**`:561562```python563>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}564>>> mock = Mock(some_attribute='eggs', **attrs)565>>> mock.some_attribute566'eggs'567>>> mock.method()5683569>>> mock.other()570Traceback (most recent call last):571 ...572KeyError573```574575Вызываемый mock, созданный с *spec* (или *spec\_set*), будет анализировать сигнатуру объекта спецификации при сопоставлении вызовов с mock. Следовательно, он может сопоставлять аргументы фактического вызова независимо от того, переданы они позиционно или по имени:576577```python578>>> def f(a, b, c): pass579...580>>> mock = Mock(spec=f)581>>> mock(1, 2, c=3)582<Mock name='mock()' id='140161580456576'>583>>> mock.assert_called_with(1, 2, 3)584>>> mock.assert_called_with(a=1, b=2, c=3)585```586587Это относится к [`assert_called_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_with), [`assert_called_once_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with), [`assert_has_calls()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls) и [`assert_any_call()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_any_call). При [*автоспецификации*](https://python-all.ru/3.4/library/unittest.mock.html#auto-speccing) это также будет применяться к вызовам методов объекта-макета.588589> Изменено в версии 3.4: Добавлен анализ сигнатуры для объектов mock с указанной спецификацией и автоспецификацией.590591#### `class unittest.mock.PropertyMock(*args, **kwargs)`592593Макет, предназначенный для использования в качестве свойства или другого дескриптора класса. [`PropertyMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.PropertyMock) предоставляет методы [`__get__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__get__) и [`__set__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__set__), позволяющие задать возвращаемое значение при его получении.594595Получение экземпляра [`PropertyMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.PropertyMock) из объекта вызывает макет без аргументов. Присваивание вызывает макет с присваиваемым значением.596597```python598>>> class Foo:599... @property600... def foo(self):601... return 'something'602... @foo.setter603... def foo(self, value):604... pass605...606>>> with patch('__main__.Foo.foo', new_callable=PropertyMock) as mock_foo:607... mock_foo.return_value = 'mockity-mock'608... this_foo = Foo()609... print(this_foo.foo)610... this_foo.foo = 6611...612mockity-mock613>>> mock_foo.mock_calls614[call(), call(6)]615```616617Из-за способа хранения атрибутов макета нельзя напрямую прикрепить [`PropertyMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.PropertyMock) к объекту-макету. Вместо этого его можно прикрепить к объекту типа макета:618619```python620>>> m = MagicMock()621>>> p = PropertyMock(return_value=3)622>>> type(m).foo = p623>>> m.foo6243625>>> p.assert_called_once_with()626```627628### 26.4.2.1. Вызов629630Объекты-макеты вызываемы. Вызов возвращает значение, установленное в атрибуте [`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value). По умолчанию возвращаемое значение – новый объект Mock; он создаётся при первом обращении к возвращаемому значению (явном или через вызов макета), но затем сохраняется и возвращается при каждом последующем вызове.631632Вызовы объекта будут записаны в таких атрибутах, как [`call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args) и [`call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list).633634Если задан [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect), то он будет вызван после записи вызова; поэтому, если `side_effect` возбуждает исключение, вызов всё равно будет записан.635636Простейший способ заставить макет возбуждать исключение при вызове – сделать [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect) классом или экземпляром исключения:637638```python639>>> m = MagicMock(side_effect=IndexError)640>>> m(1, 2, 3)641Traceback (most recent call last):642 ...643IndexError644>>> m.mock_calls645[call(1, 2, 3)]646>>> m.side_effect = KeyError('Bang!')647>>> m('two', 'three', 'four')648Traceback (most recent call last):649 ...650KeyError: 'Bang!'651>>> m.mock_calls652[call(1, 2, 3), call('two', 'three', 'four')]653```654655Если `side_effect` является функцией, то возвращаемое этой функцией значение будет возвращаться при вызовах макета. Функция `side_effect` вызывается с теми же аргументами, что и макет. Это позволяет динамически менять возвращаемое значение вызова в зависимости от входных данных:656657```python658>>> def side_effect(value):659... return value + 1660...661>>> m = MagicMock(side_effect=side_effect)662>>> m(1)6632664>>> m(2)6653666>>> m.mock_calls667[call(1), call(2)]668```669670Если нужно, чтобы макет по-прежнему возвращал значение по умолчанию (новый макет) или любое установленное возвращаемое значение, есть два способа. Либо вернуть `mock.return_value` изнутри `side_effect`, либо вернуть [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT):671672```python673>>> m = MagicMock()674>>> def side_effect(*args, **kwargs):675... return m.return_value676...677>>> m.side_effect = side_effect678>>> m.return_value = 3679>>> m()6803681>>> def side_effect(*args, **kwargs):682... return DEFAULT683...684>>> m.side_effect = side_effect685>>> m()6863687```688689Чтобы удалить `side_effect` и вернуться к поведению по умолчанию, установите `side_effect` в `None`:690691```python692>>> m = MagicMock(return_value=6)693>>> def side_effect(*args, **kwargs):694... return 3695...696>>> m.side_effect = side_effect697>>> m()6983699>>> m.side_effect = None700>>> m()7016702```703704`side_effect` также может быть любым итерируемым объектом. При повторных вызовах макета будут возвращаться значения из итерируемого объекта (пока он не исчерпается и не будет возбуждено [`StopIteration`](https://python-all.ru/3.4/library/exceptions.html#StopIteration)):705706```python707>>> m = MagicMock(side_effect=[1, 2, 3])708>>> m()7091710>>> m()7112712>>> m()7133714>>> m()715Traceback (most recent call last):716 ...717StopIteration718```719720Если какие-либо элементы итератора являются исключениями, они будут вызваны вместо того, чтобы быть возвращёнными:721722```python723>>> iterable = (33, ValueError, 66)724>>> m = MagicMock(side_effect=iterable)725>>> m()72633727>>> m()728Traceback (most recent call last):729 ...730ValueError731>>> m()73266733```734735### 26.4.2.2. Удаление атрибутов736737Объекты Mock создают атрибуты по запросу. Это позволяет им притворяться объектами любого типа.738739Возможно, потребуется, чтобы mock-объект возвращал `False` на вызов [`hasattr()`](https://python-all.ru/3.4/library/functions.html#hasattr) или вызывал [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError) при запросе атрибута. Это можно сделать, передав объект в качестве `spec` для mock, но это не всегда удобно.740741Атрибуты «блокируются» их удалением. После удаления обращение к атрибуту вызовет [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).742743```python744>>> mock = MagicMock()745>>> hasattr(mock, 'm')746True747>>> del mock.m748>>> hasattr(mock, 'm')749False750>>> del mock.f751>>> mock.f752Traceback (most recent call last):753 ...754AttributeError: f755```756757### 26.4.2.3. Имена mock'ов и атрибут name758759Поскольку «name» – это аргумент конструктора [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock), если требуется, чтобы mock-объект имел атрибут «name», его нельзя просто передать при создании. Есть две альтернативы. Один из вариантов – использовать [`configure_mock()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.configure_mock):760761```python762>>> mock = MagicMock()763>>> mock.configure_mock(name='my_name')764>>> mock.name765'my_name'766```767768Более простой вариант – просто установить атрибут «name» после создания макета:769770```python771>>> mock = MagicMock()772>>> mock.name = "foo"773```774775### 26.4.2.4. Прикрепление моков в качестве атрибутов776777Когда mock прикрепляется как атрибут другого mock (или как возвращаемое значение), он становится «дочерним» по отношению к этому mock. Вызовы к дочернему объекту записываются в атрибуты [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) родительского объекта. Это полезно для настройки дочерних mock'ов и последующего их прикрепления к родительскому, или для прикрепления mock'ов к родительскому, который записывает все вызовы к дочерним и позволяет делать утверждения о порядке вызовов между mock'ами:778779```python780>>> parent = MagicMock()781>>> child1 = MagicMock(return_value=None)782>>> child2 = MagicMock(return_value=None)783>>> parent.child1 = child1784>>> parent.child2 = child2785>>> child1(1)786>>> child2(2)787>>> parent.mock_calls788[call.child1(1), call.child2(2)]789```790791Исключение составляет случай, когда у макета есть имя. Это позволяет предотвратить «родительскую связь», если по какой-то причине вы не хотите, чтобы это происходило.792793```python794>>> mock = MagicMock()795>>> not_a_child = MagicMock(name='not-a-child')796>>> mock.attribute = not_a_child797>>> mock.attribute()798<MagicMock name='not-a-child()' id='...'>799>>> mock.mock_calls800[]801```802803Mock'ы, создаваемые [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), автоматически получают имена. Чтобы прикрепить именованные mock'и к родительскому, используется метод [`attach_mock()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.attach_mock):804805```python806>>> thing1 = object()807>>> thing2 = object()808>>> parent = MagicMock()809>>> with patch('__main__.thing1', return_value=None) as child1:810... with patch('__main__.thing2', return_value=None) as child2:811... parent.attach_mock(child1, 'child1')812... parent.attach_mock(child2, 'child2')813... child1('one')814... child2('two')815...816>>> parent.mock_calls817[call.child1('one'), call.child2('two')]818```819820| [\[1\]](https://python-all.ru/3.4/library/unittest.mock.html#id1) | The only exceptions are magic methods and attributes (those that have leading and trailing double underscores). Mock doesn’t create these but instead raises an [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError). This is because the interpreter will often implicitly request these methods, and gets *very* confused to get a new Mock object when it expects a magic method. If you need magic method support see [*magic methods*](https://python-all.ru/3.4/library/unittest.mock.html#magic-methods). |821| --- | --- |822823## 26.4.3. Патчеры824825Декораторы patch используются для патчинга объектов только в пределах области видимости функции, которую они декорируют. Они автоматически обрабатывают отмену патчинга, даже если возникают исключения. Все эти функции также могут использоваться в операторах with или в качестве декораторов классов.826827### 26.4.3.1. patch828829> **Примечание**830>831> [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) прост в использовании. Ключевой момент – выполнять патчинг в правильном пространстве имен. См. раздел [«где патчить»](https://python-all.ru/3.4/library/unittest.mock.html#id4).832833#### `unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`834835[`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) работает как декоратор функции, декоратор класса или контекстный менеджер. Внутри тела функции или оператора with *target* заменяется объектом *new*. При выходе из функции/оператора with патч отменяется.836837Если *new* опущен, то target заменяется на [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock). Если [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) используется как декоратор и *new* опущен, то созданный mock передаётся как дополнительный аргумент декорируемой функции. Если [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) используется как контекстный менеджер, созданный mock возвращается контекстным менеджером.838839*target* должен быть строкой вида `'package.module.ClassName'`. *target* импортируется, и указанный объект заменяется объектом *new*, поэтому *target* должен быть импортируемым из окружения, в котором вызывается [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch). target импортируется при выполнении декорированной функции, а не во время декорирования.840841Именованные аргументы *spec* и *spec\_set* передаются в [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock), если patch создаёт его.842843Кроме того, можно передать `spec=True` или `spec_set=True`, что заставит patch передать заменяемый объект в качестве spec/spec\_set.844845*new\_callable* позволяет указать другой класс или вызываемый объект, который будет вызван для создания объекта *new*. По умолчанию используется [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock).846847Более мощной формой *spec* является *autospec*. Если установить `autospec=True`, то mock будет создан со spec от заменяемого объекта. Все атрибуты mock также будут иметь spec соответствующего атрибута заменяемого объекта. Методы и функции, которые заменяются mock, будут проверять свои аргументы и вызывать [`TypeError`](https://python-all.ru/3.4/library/exceptions.html#TypeError) при вызове с неверной сигнатурой. Для mock'ов, заменяющих класс, их возвращаемое значение («экземпляр») будет иметь тот же spec, что и класс. См. функцию [`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) и раздел [*Autospeccing*](https://python-all.ru/3.4/library/unittest.mock.html#auto-speccing).848849Вместо `autospec=True` можно передать `autospec=some_object`, чтобы использовать произвольный объект в качестве spec вместо заменяемого.850851По умолчанию [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) не сможет заменить атрибуты, которые не существуют. Если передать `create=True`, и атрибут не существует, patch создаст его при вызове патченной функции, а затем снова удалит. Это полезно для написания тестов на атрибуты, которые рабочий код создаёт во время выполнения. По умолчанию эта возможность отключена, так как может быть опасной. С ней можно писать успешные тесты на API, которых на самом деле не существует!852853Patch можно использовать как декоратор класса `TestCase`. Он работает, декорируя каждый тестовый метод в классе. Это уменьшает шаблонный код, когда тестовые методы имеют общий набор патчей. [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) находит тесты, ища методы, имена которых начинаются с `patch.TEST_PREFIX`. По умолчанию это `'test'`, что совпадает с тем, как [`unittest`](https://python-all.ru/3.4/library/unittest.html#module-unittest) находит тесты. Можно указать альтернативный префикс, установив `patch.TEST_PREFIX`.854855Patch можно использовать как контекстный менеджер с оператором with. В этом случае патчинг применяется к блоку с отступом после оператора with. Если используется «as», то заменённый объект будет привязан к имени после «as»; это очень полезно, если [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) создаёт mock-объект.856857[`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) принимает произвольные именованные аргументы. Они будут переданы [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) (или *new\_callable*) при создании.858859`patch.dict(...)`, `patch.multiple(...)` и `patch.object(...)` доступны для других сценариев использования.860861[`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) в качестве декоратора функции, создающий mock и передающий его в декорированную функцию:862863```python864>>> @patch('__main__.SomeClass')865... def function(normal_argument, mock_class):866... print(mock_class is SomeClass)867...868>>> function(None)869True870```871872Патчинг класса заменяет класс на [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) *экземпляр*. Если класс инстанциируется в тестируемом коде, то будет использоваться [`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value) mock'а.873874Если класс инстанциируется несколько раз, можно использовать [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect), чтобы каждый раз возвращать новый mock. В качестве альтернативы можно установить *return\_value* в любое значение.875876Чтобы настроить возвращаемые значения методов *экземпляров* патченного класса, это нужно делать на `return_value`. Например:877878```python879>>> class Class:880... def method(self):881... pass882...883>>> with patch('__main__.Class') as MockClass:884... instance = MockClass.return_value885... instance.method.return_value = 'foo'886... assert Class() is instance887... assert Class().method() == 'foo'888...889```890891Если используется *spec* или *spec\_set*, и [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) заменяет *класс*, то возвращаемое значение созданного mock будет иметь тот же spec.892893```python894>>> Original = Class895>>> patcher = patch('__main__.Class', spec=True)896>>> MockClass = patcher.start()897>>> instance = MockClass()898>>> assert isinstance(instance, Original)899>>> patcher.stop()900```901902Аргумент *new\_callable* полезен, когда требуется использовать альтернативный класс вместо [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) для создаваемого mock. Например, если нужно, чтобы использовался [`NonCallableMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.NonCallableMock):903904```python905>>> thing = object()906>>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing:907... assert thing is mock_thing908... thing()909...910Traceback (most recent call last):911 ...912TypeError: 'NonCallableMock' object is not callable913```914915Ещё один вариант использования – замена объекта экземпляром [`io.StringIO`](https://python-all.ru/3.4/library/io.html#io.StringIO):916917```python918>>> from io import StringIO919>>> def foo():920... print('Something')921...922>>> @patch('sys.stdout', new_callable=StringIO)923... def test(mock_stdout):924... foo()925... assert mock_stdout.getvalue() == 'Something\n'926...927>>> test()928```929930Когда [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) создаёт мок, обычно первым делом требуется настроить этот мок. Часть настройки можно выполнить в самом вызове patch. Любые произвольные ключевые слова, переданные в вызов, будут использованы для установки атрибутов созданного мока:931932```python933>>> patcher = patch('__main__.thing', first='one', second='two')934>>> mock_thing = patcher.start()935>>> mock_thing.first936'one'937>>> mock_thing.second938'two'939```940941Кроме того, можно настроить не только атрибуты созданного мока, но и атрибуты дочерних моков, такие как [`return_value`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.return_value) и [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect). Их нельзя передать напрямую в качестве ключевых аргументов, но словарь с этими ключами можно развернуть в вызов [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) с помощью `**`:942943```python944>>> config = {'method.return_value': 3, 'other.side_effect': KeyError}945>>> patcher = patch('__main__.thing', **config)946>>> mock_thing = patcher.start()947>>> mock_thing.method()9483949>>> mock_thing.other()950Traceback (most recent call last):951 ...952KeyError953```954955### 26.4.3.2. patch.object956957#### `patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`958959Заменяет именованный член (*атрибут*) объекта (*цель*) на мок-объект.960961[`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) можно использовать как декоратор, декоратор класса или контекстный менеджер. Аргументы *new*, *spec*, *create*, *spec\_set*, *autospec* и *new\_callable* имеют тот же смысл, что и в [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch). Как и [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), [`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) принимает произвольные ключевые аргументы для настройки создаваемого объекта-мока.962963При использовании в качестве декоратора класса [`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) учитывает `patch.TEST_PREFIX` для выбора методов, которые нужно обернуть.964965[`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) можно вызывать как с тремя, так и с двумя аргументами. Форма с тремя аргументами принимает объект для подмены, имя атрибута и объект, на который нужно заменить атрибут.966967При вызове с двумя аргументами заменяющий объект опускается, и мок создаётся и передаётся как дополнительный аргумент в декорируемую функцию:968969```python970>>> @patch.object(SomeClass, 'class_method')971... def test(mock_method):972... SomeClass.class_method(3)973... mock_method.assert_called_with(3)974...975>>> test()976```977978*spec*, *create* и остальные аргументы [`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) имеют тот же смысл, что и в [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch).979980### 26.4.3.3. patch.dict981982#### `patch.dict(in_dict, values=(), clear=False, **kwargs)`983984Исправляет словарь или подобный словарю объект и восстанавливает его исходное состояние после завершения теста.985986*in\_dict* может быть словарём или контейнером, подобным отображению. Если это отображение, оно должно как минимум поддерживать получение, установку и удаление элементов, а также итерацию по ключам.987988*in\_dict* также может быть строкой, задающей имя словаря, который затем будет получен через импорт.989990*values* может быть словарём значений для установки в словаре. *values* также может быть итерируемым объектом, содержащим пары `(key, value)`.991992Если *clear* равен true, то словарь будет очищен перед установкой новых значений.993994[`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) также можно вызывать с произвольными ключевыми аргументами для установки значений в словаре.995996[`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) можно использовать как контекстный менеджер, декоратор или декоратор класса. При использовании в качестве декоратора класса [`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) учитывает `patch.TEST_PREFIX` для выбора методов, которые нужно обернуть.997998[`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) можно использовать для добавления элементов в словарь или просто чтобы позволить тесту изменить словарь и гарантировать, что после завершения теста словарь будет восстановлен.9991000```python1001>>> foo = {}1002>>> with patch.dict(foo, {'newkey': 'newvalue'}):1003... assert foo == {'newkey': 'newvalue'}1004...1005>>> assert foo == {}1006```10071008```python1009>>> import os1010>>> with patch.dict('os.environ', {'newkey': 'newvalue'}):1011... print(os.environ['newkey'])1012...1013newvalue1014>>> assert 'newkey' not in os.environ1015```10161017В вызове [`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) можно использовать ключевые слова для установки значений в словаре:10181019```python1020>>> mymodule = MagicMock()1021>>> mymodule.function.return_value = 'fish'1022>>> with patch.dict('sys.modules', mymodule=mymodule):1023... import mymodule1024... mymodule.function('some', 'args')1025...1026'fish'1027```10281029[`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) можно использовать с объектами, похожими на словарь, которые на самом деле не являются словарями. Минимально они должны поддерживать получение, установку и удаление элементов, а также либо итерацию, либо проверку членства. Это соответствует магическим методам [`__getitem__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__getitem__), [`__setitem__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__setitem__), [`__delitem__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__delitem__) и либо [`__iter__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__iter__), либо [`__contains__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__contains__).10301031```python1032>>> class Container:1033... def __init__(self):1034... self.values = {}1035... def __getitem__(self, name):1036... return self.values[name]1037... def __setitem__(self, name, value):1038... self.values[name] = value1039... def __delitem__(self, name):1040... del self.values[name]1041... def __iter__(self):1042... return iter(self.values)1043...1044>>> thing = Container()1045>>> thing['one'] = 11046>>> with patch.dict(thing, one=2, two=3):1047... assert thing['one'] == 21048... assert thing['two'] == 31049...1050>>> assert thing['one'] == 11051>>> assert list(thing) == ['one']1052```10531054### 26.4.3.4. patch.multiple10551056#### `patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`10571058Выполняет несколько патчей за один вызов. Принимает объект для патча (либо сам объект, либо строку для его импорта) и именованные аргументы для патчей:10591060```python1061with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'):1062 ...1063```10641065Используйте [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT) в качестве значения, если хотите, чтобы [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) создавал моки за вас. В этом случае созданные моки передаются в декорированную функцию как ключевые аргументы, а при использовании [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) в качестве контекстного менеджера возвращается словарь.10661067[`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) can be used as a decorator, class decorator or a context manager. The arguments *spec*, *spec\_set*, *create*, *autospec* and *new\_callable* have the same meaning as for [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch). These arguments will be applied to *all* patches done by [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple).10681069При использовании в качестве декоратора класса [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) учитывает `patch.TEST_PREFIX` для выбора методов, которые нужно обернуть.10701071Если вы хотите, чтобы [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) создавал моки за вас, вы можете использовать [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT) в качестве значения. Если вы используете [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) как декоратор, то созданные моки передаются в декорированную функцию по ключу.10721073```python1074>>> thing = object()1075>>> other = object()1076```10771078```python1079>>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)1080... def test_function(thing, other):1081... assert isinstance(thing, MagicMock)1082... assert isinstance(other, MagicMock)1083...1084>>> test_function()1085```10861087[`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) может быть вложен в другие декораторы `patch`, но аргументы, передаваемые по ключу, должны указываться *после* любых стандартных аргументов, создаваемых [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch):10881089```python1090>>> @patch('sys.exit')1091... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)1092... def test_function(mock_exit, other, thing):1093... assert 'other' in repr(other)1094... assert 'thing' in repr(thing)1095... assert 'exit' in repr(mock_exit)1096...1097>>> test_function()1098```10991100Если [`patch.multiple()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.multiple) используется как контекстный менеджер, то возвращаемое им значение – это словарь, в котором созданные моки сгруппированы по имени:11011102```python1103>>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values:1104... assert 'other' in repr(values['other'])1105... assert 'thing' in repr(values['thing'])1106... assert values['thing'] is thing1107... assert values['other'] is other1108...1109```11101111### 26.4.3.5. Методы patch: start и stop11121113У всех патчеров есть методы `start()` и `stop()`. Они упрощают выполнение подмен в методах `setUp` или в тех случаях, когда нужно сделать несколько подмен, не вкладывая декораторы или операторы with.11141115Для их использования вызовите [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), [`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object) или [`patch.dict()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.dict) как обычно и сохраните ссылку на возвращаемый объект `patcher`. Затем вы можете вызвать `start()`, чтобы применить подмену, и `stop()`, чтобы отменить её.11161117Если вы используете [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) для создания мока, то он будет возвращён вызовом `patcher.start`.11181119```python1120>>> patcher = patch('package.module.ClassName')1121>>> from package import module1122>>> original = module.ClassName1123>>> new_mock = patcher.start()1124>>> assert module.ClassName is not original1125>>> assert module.ClassName is new_mock1126>>> patcher.stop()1127>>> assert module.ClassName is original1128>>> assert module.ClassName is not new_mock1129```11301131Типичный вариант использования – выполнение нескольких подмен в методе `setUp` класса `TestCase`:11321133```python1134>>> class MyTest(TestCase):1135... def setUp(self):1136... self.patcher1 = patch('package.module.Class1')1137... self.patcher2 = patch('package.module.Class2')1138... self.MockClass1 = self.patcher1.start()1139... self.MockClass2 = self.patcher2.start()1140...1141... def tearDown(self):1142... self.patcher1.stop()1143... self.patcher2.stop()1144...1145... def test_something(self):1146... assert package.module.Class1 is self.MockClass11147... assert package.module.Class2 is self.MockClass21148...1149>>> MyTest('test_something').run()1150```11511152> **Внимание**1153>1154> При использовании этого подхода необходимо убедиться, что подмена отменяется вызовом `stop`. Это может оказаться сложнее, чем кажется, потому что если в методе `setUp` возникнет исключение, то `tearDown` не будет вызван. [`unittest.TestCase.addCleanup()`](https://python-all.ru/3.4/library/unittest.html#unittest.TestCase.addCleanup) упрощает эту задачу:1155>1156> ```python1157> >>> class MyTest(TestCase):1158> ... def setUp(self):1159> ... patcher = patch('package.module.Class')1160> ... self.MockClass = patcher.start()1161> ... self.addCleanup(patcher.stop)1162> ...1163> ... def test_something(self):1164> ... assert package.module.Class is self.MockClass1165> ...1166> ```1167>1168> В качестве дополнительного бонуса вам больше не нужно хранить ссылку на объект `patcher`.11691170Также можно остановить все патчи, которые были запущены с помощью [`patch.stopall()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.stopall).11711172#### `patch.stopall()`11731174Останавливает все активные патчи. Останавливает только патчи, запущенные с помощью `start`.11751176### 26.4.3.6. TEST\_PREFIX11771178Все патчеры можно использовать в качестве декораторов классов. При таком использовании они оборачивают каждый тестовый метод класса. Патчеры распознают методы, которые начинаются с `'test'`, как тестовые. Это тот же способ, которым [`unittest.TestLoader`](https://python-all.ru/3.4/library/unittest.html#unittest.TestLoader) по умолчанию находит тестовые методы.11791180Возможно, вы захотите использовать другой префикс для своих тестов. Вы можете сообщить патчерам другой префикс, установив `patch.TEST_PREFIX`:11811182```python1183>>> patch.TEST_PREFIX = 'foo'1184>>> value = 31185>>>1186>>> @patch('__main__.value', 'not three')1187... class Thing:1188... def foo_one(self):1189... print(value)1190... def foo_two(self):1191... print(value)1192...1193>>>1194>>> Thing().foo_one()1195not three1196>>> Thing().foo_two()1197not three1198>>> value119931200```12011202### 26.4.3.7. Вложение декораторов патчей12031204Если нужно выполнить несколько замен, можно просто наложить декораторы друг на друга.12051206Можно накладывать несколько декораторов патча, используя такой шаблон:12071208```python1209>>> @patch.object(SomeClass, 'class_method')1210... @patch.object(SomeClass, 'static_method')1211... def test(mock1, mock2):1212... assert SomeClass.static_method is mock11213... assert SomeClass.class_method is mock21214... SomeClass.static_method('foo')1215... SomeClass.class_method('bar')1216... return mock1, mock21217...1218>>> mock1, mock2 = test()1219>>> mock1.assert_called_once_with('foo')1220>>> mock2.assert_called_once_with('bar')1221```12221223Обратите внимание: декораторы применяются снизу вверх. Это стандартный порядок применения декораторов в Python. Порядок созданных заглушек, передаваемых в тестовую функцию, соответствует этому порядку.12241225### 26.4.3.8. Где патчить12261227[`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) работает, (временно) заменяя объект, на который указывает *имя*, другим объектом. На один и тот же объект может указывать много имён, поэтому для корректной работы патча необходимо убедиться, что патчится имя, используемое тестируемой системой.12281229Основной принцип: патч применяется там, где объект *ищется*, а это не обязательно то же место, где он определён. Несколько примеров помогут прояснить это.12301231Представим проект, который нужно протестировать, со следующей структурой:12321233```python1234a.py1235 -> Defines SomeClass12361237b.py1238 -> from a import SomeClass1239 -> some_function instantiates SomeClass1240```12411242Теперь мы хотим протестировать `some_function`, но подменить `SomeClass` с помощью [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch). Проблема в том, что когда мы импортируем модуль b (а нам придётся это сделать), он импортирует `SomeClass` из модуля a. Если мы используем [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) для подмены `a.SomeClass`, то это не повлияет на наш тест; модуль b уже содержит ссылку на *настоящий* `SomeClass`, и кажется, что наш патч не сработал.12431244Ключевой момент – патчить `SomeClass` там, где он используется (или где происходит его поиск). В данном случае `some_function` будет искать `SomeClass` в модуле b, куда мы его импортировали. Патч должен выглядеть так:12451246```python1247@patch('b.SomeClass')1248```12491250Однако рассмотрим альтернативный сценарий, когда вместо `from a import SomeClass` модуль b выполняет `import a`, а `some_function` использует `a.SomeClass`. Обе эти формы импорта распространены. В этом случае класс, который мы хотим подменить, ищется в модуле, поэтому мы должны патчить `a.SomeClass` вместо:12511252```python1253@patch('a.SomeClass')1254```12551256### 26.4.3.9. Патчинг дескрипторов и прокси-объектов12571258И [patch](https://python-all.ru/3.4/library/unittest.mock.html#patch), и [patch.object](https://python-all.ru/3.4/library/unittest.mock.html#patch-object) корректно заменяют и восстанавливают дескрипторы: методы класса, статические методы и свойства. Заменять их следует на *классе*, а не на экземпляре. Они также работают с *некоторыми* объектами, проксирующими доступ к атрибутам, например, [объект настроек Django](https://python-all.ru/3.4/library/unittest.mock.html).12591260## 26.4.4. MagicMock и поддержка магических методов12611262### 26.4.4.1. Подмена магических методов12631264[`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) поддерживает подмену методов протоколов Python, также известных как «магические методы». Это позволяет мок-объектам заменять контейнеры или другие объекты, реализующие протоколы Python.12651266Поскольку магические методы ищутся иначе, чем обычные методы [\[2\]](https://python-all.ru/3.4/library/unittest.mock.html#id7), эта поддержка была реализована специально. Это означает, что поддерживаются только определённые магические методы. Список поддерживаемых методов включает *почти* все. Если каких-то не хватает, пожалуйста, сообщите.12671268Магические методы подменяются установкой нужного метода в функцию или экземпляр мока. Если используется функция, она *обязана* принимать `self` в качестве первого аргумента [\[3\]](https://python-all.ru/3.4/library/unittest.mock.html#id8).12691270```python1271>>> def __str__(self):1272... return 'fooble'1273...1274>>> mock = Mock()1275>>> mock.__str__ = __str__1276>>> str(mock)1277'fooble'1278```12791280```python1281>>> mock = Mock()1282>>> mock.__str__ = Mock()1283>>> mock.__str__.return_value = 'fooble'1284>>> str(mock)1285'fooble'1286```12871288```python1289>>> mock = Mock()1290>>> mock.__iter__ = Mock(return_value=iter([]))1291>>> list(mock)1292[]1293```12941295Один из вариантов использования – подмена объектов, используемых в качестве контекстных менеджеров в инструкции [`with`](https://python-all.ru/3.4/reference/compound_stmts.html#with):12961297```python1298>>> mock = Mock()1299>>> mock.__enter__ = Mock(return_value='foo')1300>>> mock.__exit__ = Mock(return_value=False)1301>>> with mock as m:1302... assert m == 'foo'1303...1304>>> mock.__enter__.assert_called_with()1305>>> mock.__exit__.assert_called_with(None, None, None)1306```13071308Вызовы магических методов не отображаются в [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls), но записываются в [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls).13091310> **Примечание**1311>1312> Если для создания мока используется именованный аргумент *spec*, то попытка установить магический метод, отсутствующий в спецификации, вызовет [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).13131314Полный список поддерживаемых магических методов:13151316- `__hash__`, `__sizeof__`, `__repr__` и `__str__`1317- `__dir__`, `__format__` и `__subclasses__`1318- `__floor__`, `__trunc__` и `__ceil__`1319- Сравнения: `__lt__`, `__gt__`, `__le__`, `__ge__`, `__eq__` и `__ne__`1320- Методы контейнеров: `__getitem__`, `__setitem__`, `__delitem__`, `__contains__`, `__len__`, `__iter__`, `__reversed__` и `__missing__`1321- Контекстный менеджер: `__enter__` и `__exit__`1322- Унарные числовые методы: `__neg__`, `__pos__` и `__invert__`1323- Числовые методы (включая правосторонние и варианты с присваиванием): `__add__`, `__sub__`, `__mul__`, `__div__`, `__truediv__`, `__floordiv__`, `__mod__`, `__divmod__`, `__lshift__`, `__rshift__`, `__and__`, `__xor__`, `__or__` и `__pow__`1324- Методы числового преобразования: `__complex__`, `__int__`, `__float__` и `__index__`1325- Методы дескрипторов: `__get__`, `__set__` и `__delete__`1326- Сериализация (pickle): `__reduce__`, `__reduce_ex__`, `__getinitargs__`, `__getnewargs__`, `__getstate__` и `__setstate__`13271328Следующие методы существуют, но *не* поддерживаются, так как либо используются в mock, либо не могут быть установлены динамически, либо могут вызывать проблемы:13291330- `__getattr__`, `__setattr__`, `__init__` и `__new__`1331- `__prepare__`, `__instancecheck__`, `__subclasscheck__`, `__del__`13321333### 26.4.4.2. Magic Mock13341335Есть две разновидности `MagicMock`: [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) и [`NonCallableMagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.NonCallableMagicMock).13361337#### `class unittest.mock.MagicMock(*args, **kw)`13381339`MagicMock` – это подкласс [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) с реализациями по умолчанию большинства магических методов. Можно использовать `MagicMock`, не настраивая магические методы вручную.13401341Параметры конструктора имеют тот же смысл, что и для [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock).13421343Если используются аргументы *spec* или *spec\_set*, то будут созданы *только* магические методы, которые существуют в спецификации.13441345#### `class unittest.mock.NonCallableMagicMock(*args, **kw)`13461347Невызываемая версия [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock).13481349Параметры конструктора имеют тот же смысл, что и для [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock), за исключением *return\_value* и *side\_effect*, которые не имеют смысла для невызываемого мока.13501351Магические методы настраиваются с помощью объектов [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock), поэтому их можно настраивать и использовать обычным образом:13521353```python1354>>> mock = MagicMock()1355>>> mock[3] = 'fish'1356>>> mock.__setitem__.assert_called_with(3, 'fish')1357>>> mock.__getitem__.return_value = 'result'1358>>> mock[2]1359'result'1360```13611362По умолчанию многие методы протокола должны возвращать объекты определенного типа. Эти методы предварительно настроены с возвращаемым значением по умолчанию, так что их можно использовать, ничего не делая, если возвращаемое значение не интересует. Вы всё еще можете *установить* возвращаемое значение вручную, если хотите изменить значение по умолчанию.13631364Методы и их значения по умолчанию:13651366- `__lt__`: NotImplemented1367- `__gt__`: NotImplemented1368- `__le__`: NotImplemented1369- `__ge__`: NotImplemented1370- `__int__`: 11371- `__contains__`: False1372- `__len__`: 11373- `__iter__`: iter(\[\])1374- `__exit__`: False1375- `__complex__`: 1j1376- `__float__`: 1.01377- `__bool__`: True1378- `__index__`: 11379- `__hash__`: хэш по умолчанию для мока1380- `__str__`: строковое представление по умолчанию для мока1381- `__sizeof__`: размер по умолчанию для мока13821383Например:13841385```python1386>>> mock = MagicMock()1387>>> int(mock)138811389>>> len(mock)139001391>>> list(mock)1392[]1393>>> object() in mock1394False1395```13961397Два метода сравнения, [`__eq__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__eq__) и [`__ne__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__ne__), являются особыми. Они выполняют сравнение на равенство по умолчанию на основе идентичности, используя атрибут [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect), если только не изменить возвращаемое значение, чтобы оно возвращало что-то другое:13981399```python1400>>> MagicMock() == 31401False1402>>> MagicMock() != 31403True1404>>> mock = MagicMock()1405>>> mock.__eq__.return_value = True1406>>> mock == 31407True1408```14091410Возвращаемое значение `MagicMock.__iter__()` может быть любым итерируемым объектом и не обязательно должно быть итератором:14111412```python1413>>> mock = MagicMock()1414>>> mock.__iter__.return_value = ['a', 'b', 'c']1415>>> list(mock)1416['a', 'b', 'c']1417>>> list(mock)1418['a', 'b', 'c']1419```14201421Если возвращаемое значение *является* итератором, то однократная итерация по нему израсходует его, и последующие итерации приведут к пустому списку:14221423```python1424>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])1425>>> list(mock)1426['a', 'b', 'c']1427>>> list(mock)1428[]1429```14301431У `MagicMock` настроены все поддерживаемые магические методы, за исключением некоторых устаревших и редко используемых. При желании их можно настроить.14321433Магические методы, которые поддерживаются, но не настроены по умолчанию в `MagicMock`:14341435- `__subclasses__`1436- `__dir__`1437- `__format__`1438- `__get__`, `__set__` и `__delete__`1439- `__reversed__` и `__missing__`1440- `__reduce__`, `__reduce_ex__`, `__getinitargs__`, `__getnewargs__`, `__getstate__` и `__setstate__`1441- `__getformat__` и `__setformat__`14421443| [\[2\]](https://python-all.ru/3.4/library/unittest.mock.html#id5) | Магические методы *должны* искаться в классе, а не в экземпляре. Разные версии Python непоследовательны в применении этого правила. Поддерживаемые методы протокола должны работать во всех поддерживаемых версиях Python. |1444| --- | --- |14451446| [\[3\]](https://python-all.ru/3.4/library/unittest.mock.html#id6) | Функция фактически прикрепляется к классу, но каждый экземпляр `Mock` остаётся изолированным от других. |1447| --- | --- |14481449## 26.4.5. Вспомогательные объекты14501451### 26.4.5.1. sentinel14521453#### `unittest.mock.sentinel`14541455Объект `sentinel` предоставляет удобный способ создания уникальных объектов для тестов.14561457Атрибуты создаются по запросу при обращении к ним по имени. Обращение к одному и тому же атрибуту всегда возвращает один и тот же объект. Возвращаемые объекты имеют понятное строковое представление (repr), чтобы сообщения об ошибках тестов были читаемыми.14581459Иногда при тестировании нужно проверить, что конкретный объект передаётся в качестве аргумента другому методу или возвращается. Нередко для этого создают именованные sentinel-объекты. [`sentinel`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.sentinel) предоставляет удобный способ создания и проверки идентичности таких объектов.14601461В этом примере мы подменяем (monkey patch) `method`, чтобы он возвращал `sentinel.some_object`:14621463```python1464>>> real = ProductionClass()1465>>> real.method = Mock(name="method")1466>>> real.method.return_value = sentinel.some_object1467>>> result = real.method()1468>>> assert result is sentinel.some_object1469>>> sentinel.some_object1470sentinel.some_object1471```14721473### 26.4.5.2. DEFAULT14741475#### `unittest.mock.DEFAULT`14761477Объект [`DEFAULT`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.DEFAULT) – это предварительно созданный sentinel (фактически `sentinel.DEFAULT`). Он может использоваться функциями [`side_effect`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.side_effect), чтобы указать, что следует использовать обычное возвращаемое значение.14781479### 26.4.5.3. call14801481#### `unittest.mock.call(*args, **kwargs)`14821483[`call()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call) – вспомогательный объект для упрощения проверок, сравнения с [`call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args), [`call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list), [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) и [`method_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.method_calls). [`call()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call) также можно использовать с [`assert_has_calls()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls).14841485```python1486>>> m = MagicMock(return_value=None)1487>>> m(1, 2, a='foo', b='bar')1488>>> m()1489>>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()]1490True1491```14921493#### `call.call_list()`14941495Для объекта call, представляющего несколько вызовов, [`call_list()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call.call_list) возвращает список всех промежуточных вызовов, а также конечного вызова.14961497`call_list` особенно полезен для проверок цепочечных вызовов. Цепочечный вызов – это несколько вызовов в одной строке кода. В результате в [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls) мока появляется несколько записей. Ручное построение последовательности вызовов может быть утомительным.14981499[`call_list()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.call.call_list) может построить последовательность вызовов из того же цепочечного вызова:15001501```python1502>>> m = MagicMock()1503>>> m(1).method(arg='foo').other('bar')(2.0)1504<MagicMock name='mock().method().other()()' id='...'>1505>>> kall = call(1).method(arg='foo').other('bar')(2.0)1506>>> kall.call_list()1507[call(1),1508 call().method(arg='foo'),1509 call().method().other('bar'),1510 call().method().other()(2.0)]1511>>> m.mock_calls == kall.call_list()1512True1513```15141515Объект `call` является кортежем из (позиционные аргументы, именованные аргументы) или (имя, позиционные аргументы, именованные аргументы) в зависимости от того, как он был создан. Когда вы создаёте их самостоятельно, это не особенно интересно, но объекты `call`, находящиеся в атрибутах [`Mock.call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args), [`Mock.call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list) и [`Mock.mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls), можно исследовать, чтобы получить отдельные аргументы, которые они содержат.15161517Объекты `call` в [`Mock.call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args) и [`Mock.call_args_list`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args_list) являются двухэлементными кортежами (позиционные аргументы, именованные аргументы), тогда как объекты `call` в [`Mock.mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls), а также те, что вы создаёте самостоятельно, – трёхэлементные кортежи (имя, позиционные аргументы, именованные аргументы).15181519Вы можете использовать их «кортежность», чтобы извлекать отдельные аргументы для более сложной интроспекции и проверок. Позиционные аргументы – это кортеж (пустой кортеж, если позиционных аргументов нет), а именованные аргументы – это словарь:15201521```python1522>>> m = MagicMock(return_value=None)1523>>> m(1, 2, 3, arg='one', arg2='two')1524>>> kall = m.call_args1525>>> args, kwargs = kall1526>>> args1527(1, 2, 3)1528>>> kwargs1529{'arg2': 'two', 'arg': 'one'}1530>>> args is kall[0]1531True1532>>> kwargs is kall[1]1533True1534```15351536```python1537>>> m = MagicMock()1538>>> m.foo(4, 5, 6, arg='two', arg2='three')1539<MagicMock name='mock.foo()' id='...'>1540>>> kall = m.mock_calls[0]1541>>> name, args, kwargs = kall1542>>> name1543'foo'1544>>> args1545(4, 5, 6)1546>>> kwargs1547{'arg2': 'three', 'arg': 'two'}1548>>> name is m.mock_calls[0][0]1549True1550```15511552### 26.4.5.4. create\_autospec15531554#### `unittest.mock.create_autospec(spec, spec_set=False, instance=False, **kwargs)`15551556Создаёт макет-объект, используя другой объект в качестве спецификации. Атрибуты макета будут использовать соответствующий атрибут объекта *spec* в качестве своей спецификации.15571558У макетируемых функций или методов будут проверяться аргументы, чтобы убедиться, что они вызываются с правильной сигнатурой.15591560Если *spec\_set* равно `True`, то попытка установить атрибуты, которые не существуют в объекте спецификации, вызовет [`AttributeError`](https://python-all.ru/3.4/library/exceptions.html#AttributeError).15611562Если класс используется в качестве спецификации, то возвращаемое значение мока (экземпляр класса) будет иметь ту же спецификацию. Класс можно использовать как спецификацию для объекта экземпляра, передав `instance=True`. Возвращаемый мок будет вызываемым, только если экземпляры мока являются вызываемыми.15631564[`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) также принимает произвольные именованные аргументы, которые передаются конструктору создаваемого мока.15651566Смотрите [*Autospeccing*](https://python-all.ru/3.4/library/unittest.mock.html#auto-speccing) с примерами использования автоспецификации с [`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) и аргумента *autospec* для [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch).15671568### 26.4.5.5. ANY15691570#### `unittest.mock.ANY`15711572Иногда требуется проверять только *некоторые* из аргументов в вызове mock, либо не обращать внимания на часть аргументов, либо извлекать их по отдельности из [`call_args`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.call_args) и выполнять более сложные проверки.15731574Чтобы игнорировать определённые аргументы, можно передавать объекты, которые сравниваются равными *чему угодно*. Тогда вызовы [`assert_called_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_with) и [`assert_called_once_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with) будут успешными независимо от того, что было передано.15751576```python1577>>> mock = Mock(return_value=None)1578>>> mock('foo', bar=object())1579>>> mock.assert_called_once_with('foo', bar=ANY)1580```15811582[`ANY`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.ANY) также можно использовать при сравнении со списками вызовов, такими как [`mock_calls`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.mock_calls):15831584```python1585>>> m = MagicMock(return_value=None)1586>>> m(1)1587>>> m(1, 2)1588>>> m(object())1589>>> m.mock_calls == [call(1), call(1, 2), ANY]1590True1591```15921593### 26.4.5.6. FILTER\_DIR15941595#### `unittest.mock.FILTER_DIR`15961597[`FILTER_DIR`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.FILTER_DIR) – это переменная уровня модуля, управляющая тем, как объекты mock реагируют на [`dir()`](https://python-all.ru/3.4/library/functions.html#dir) (только для Python 2.6 и новее). Значение по умолчанию – `True`, которое использует фильтрацию, описанную ниже, чтобы показывать только полезные члены. Если такая фильтрация не устраивает или её нужно отключить для диагностики, установите `mock.FILTER_DIR = False`.15981599При включённой фильтрации `dir(some_mock)` показывает только полезные атрибуты и будет включать любые динамически созданные атрибуты, которые обычно не отображаются. Если mock был создан с *spec* (или, конечно, *autospec*), то отображаются все атрибуты оригинала, даже если к ним ещё не обращались:16001601```python1602>>> dir(Mock())1603['assert_any_call',1604 'assert_called_once_with',1605 'assert_called_with',1606 'assert_has_calls',1607 'attach_mock',1608 ...1609>>> from urllib import request1610>>> dir(Mock(spec=request))1611['AbstractBasicAuthHandler',1612 'AbstractDigestAuthHandler',1613 'AbstractHTTPHandler',1614 'BaseHandler',1615 ...1616```16171618Многие не очень полезные (частные для [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock), а не для того объекта, который замещается) атрибуты с префиксами из одного и двух подчёркиваний были отфильтрованы из результата вызова [`dir()`](https://python-all.ru/3.4/library/functions.html#dir) для [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock). Если такое поведение не устраивает, его можно отключить, установив переключатель уровня модуля [`FILTER_DIR`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.FILTER_DIR):16191620```python1621>>> from unittest import mock1622>>> mock.FILTER_DIR = False1623>>> dir(mock.Mock())1624['_NonCallableMock__get_return_value',1625 '_NonCallableMock__get_side_effect',1626 '_NonCallableMock__return_value_doc',1627 '_NonCallableMock__set_return_value',1628 '_NonCallableMock__set_side_effect',1629 '__call__',1630 '__class__',1631 ...1632```16331634В качестве альтернативы можно просто использовать `vars(my_mock)` (члены экземпляра) и `dir(type(my_mock))` (члены типа), чтобы обойти фильтрацию независимо от `mock.FILTER_DIR`.16351636### 26.4.5.7. mock\_open16371638#### `unittest.mock.mock_open(mock=None, read_data=None)`16391640> Вспомогательная функция для создания mock, заменяющего использование [`open()`](https://python-all.ru/3.4/library/functions.html#open). Она работает для [`open()`](https://python-all.ru/3.4/library/functions.html#open), вызванного напрямую или используемого в качестве контекстного менеджера.1641>1642> Аргумент *mock* – это объект mock для настройки. Если `None` (значение по умолчанию), то будет создан [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) с API, ограниченным методами или атрибутами, доступными для стандартных файловых дескрипторов.1643>1644> *read\_data* – это строка для методов `read()`, [`readline()`](https://python-all.ru/3.4/library/io.html#io.IOBase.readline) и [`readlines()`](https://python-all.ru/3.4/library/io.html#io.IOBase.readlines) файлового дескриптора, которые должны её возвращать. Вызовы этих методов будут брать данные из *read\_data*, пока они не закончатся. Реализация mock для этих методов довольно проста: каждый раз при вызове *mock* *read\_data* перематывается в начало. Если требуется более тонкое управление данными, передаваемыми тестируемому коду, придётся настроить этот mock самостоятельно. Если этого недостаточно, один из пакетов для файловой системы в памяти на [PyPI](https://python-all.ru/3.4/library/unittest.mock.html) может предоставить реалистичную файловую систему для тестирования.16451646Изменено в версии 3.4: Добавлена поддержка [`readline()`](https://python-all.ru/3.4/library/io.html#io.IOBase.readline) и [`readlines()`](https://python-all.ru/3.4/library/io.html#io.IOBase.readlines). Реализация mock для `read()` изменена так, чтобы потреблять *read\_data*, а не возвращать его при каждом вызове.16471648Изменено в версии 3.4.4: Теперь *read\_data* сбрасывается при каждом вызове *mock*.16491650Использование [`open()`](https://python-all.ru/3.4/library/functions.html#open) в качестве контекстного менеджера – отличный способ гарантировать правильное закрытие файловых дескрипторов, и он становится обычной практикой:16511652```python1653with open('/some/path', 'w') as f:1654 f.write('something')1655```16561657Проблема в том, что даже если мы замещаем вызов [`open()`](https://python-all.ru/3.4/library/functions.html#open), именно *возвращённый объект* используется как контекстный менеджер (и у него вызываются [`__enter__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__enter__) и [`__exit__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__exit__)).16581659Создание моков для контекстных менеджеров с помощью [`MagicMock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.MagicMock) – достаточно распространённая и сложная задача, поэтому вспомогательная функция оказывается полезной.16601661```python1662>>> m = mock_open()1663>>> with patch('__main__.open', m, create=True):1664... with open('foo', 'w') as h:1665... h.write('some stuff')1666...1667>>> m.mock_calls1668[call('foo', 'w'),1669 call().__enter__(),1670 call().write('some stuff'),1671 call().__exit__(None, None, None)]1672>>> m.assert_called_once_with('foo', 'w')1673>>> handle = m()1674>>> handle.write.assert_called_once_with('some stuff')1675```16761677А для чтения файлов:16781679```python1680>>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m:1681... with open('foo') as h:1682... result = h.read()1683...1684>>> m.assert_called_once_with('foo')1685>>> assert result == 'bibble'1686```16871688### 26.4.5.8. Autospeccing16891690Autospeccing основан на существующей возможности `spec` в mock. Он ограничивает API mock'ов API исходного объекта (спецификации), но делает это рекурсивно (реализовано лениво), так что атрибуты mock'ов имеют только то же API, что и атрибуты спецификации. Кроме того, замещаемые функции/методы имеют ту же сигнатуру вызова, что и оригиналы, поэтому они возбуждают [`TypeError`](https://python-all.ru/3.4/library/exceptions.html#TypeError) при неправильном вызове.16911692Прежде чем я объясню, как работает автоспекинг, вот почему он нужен.16931694[`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) – очень мощный и гибкий объект, но у него есть два недостатка при использовании для замещения объектов тестируемой системы. Один из этих недостатков связан с API [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock), а другой – более общая проблема использования mock-объектов.16951696Сначала проблема, специфичная для [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock). [`Mock`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock) имеет два метода проверок, которые чрезвычайно удобны: [`assert_called_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_with) и [`assert_called_once_with()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with).16971698```python1699>>> mock = Mock(name='Thing', return_value=None)1700>>> mock(1, 2, 3)1701>>> mock.assert_called_once_with(1, 2, 3)1702>>> mock(1, 2, 3)1703>>> mock.assert_called_once_with(1, 2, 3)1704Traceback (most recent call last):1705 ...1706AssertionError: Expected 'mock' to be called once. Called 2 times.1707```17081709Поскольку mock-объекты автоматически создают атрибуты по требованию и позволяют вызывать их с произвольными аргументами, опечатка в имени одного из этих методов проверок приводит к тому, что проверка просто исчезает:17101711```pycon1712>>> mock = Mock(name='Thing', return_value=None)1713>>> mock(1, 2, 3)1714>>> mock.assret_called_once_with(4, 5, 6)1715```17161717Из-за опечатки тесты могут проходить молча и неправильно.17181719The second issue is more general to mocking. If you refactor some of your code, rename members and so on, any tests for code that is still using the *old api* but uses mocks instead of the real objects will still pass. This means your tests can all pass even though your code is broken.17201721Обратите внимание, что это ещё одна причина, по которой нужны интеграционные тесты, а не только модульные. Тестировать всё изолированно – это хорошо, но если вы не тестируете, как ваши модули «соединены вместе», всё ещё остаётся много места для ошибок, которые тесты могли бы выявить.17221723`mock` уже предоставляет возможность для решения этой проблемы, называемую speccing. Если использовать класс или экземпляр в качестве `spec` для mock, то можно обращаться только к тем атрибутам mock, которые существуют в реальном классе:17241725```python1726>>> from urllib import request1727>>> mock = Mock(spec=request.Request)1728>>> mock.assret_called_with1729Traceback (most recent call last):1730 ...1731AttributeError: Mock object has no attribute 'assret_called_with'1732```17331734Spec применяется только к самому mock, поэтому у нас всё ещё есть та же проблема с любыми методами на mock:17351736```pycon1737>>> mock.has_data()1738<mock.Mock object at 0x...>1739>>> mock.has_data.assret_called_with()1740```17411742Авто-спецификация решает эту проблему. Можно либо передать `autospec=True` в [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) / [`patch.object()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch.object), либо использовать функцию [`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) для создания mock со спецификацией. Если использовать аргумент `autospec=True` для [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), то объект, который замещается, будет использоваться как объект спецификации. Поскольку спецификация выполняется «лениво» (спецификация создаётся по мере обращения к атрибутам mock), её можно использовать с очень сложными или глубоко вложенными объектами (например, модулями, которые импортируют модули, которые импортируют модули) без значительного снижения производительности.17431744Вот пример его использования:17451746```python1747>>> from urllib import request1748>>> patcher = patch('__main__.request', autospec=True)1749>>> mock_request = patcher.start()1750>>> request is mock_request1751True1752>>> mock_request.Request1753<MagicMock name='request.Request' spec='Request' id='...'>1754```17551756Видно, что `request.Request` имеет спецификацию. `request.Request` принимает два аргумента в конструкторе (один из которых – *self*). Вот что произойдёт, если вызвать его неправильно:17571758```python1759>>> req = request.Request()1760Traceback (most recent call last):1761 ...1762TypeError: <lambda>() takes at least 2 arguments (1 given)1763```17641765Spec также применяется к инстанцированным классам (т.е. возвращаемому значению specced-моков):17661767```python1768>>> req = request.Request('foo')1769>>> req1770<NonCallableMagicMock name='request.Request()' spec='Request' id='...'>1771```17721773Объекты `Request` не являются вызываемыми, поэтому возвращаемое значение при создании нашего замещённого `request.Request` – это не вызываемый mock. При наличии спецификации любые опечатки в утверждениях будут вызывать правильную ошибку:17741775```python1776>>> req.add_header('spam', 'eggs')1777<MagicMock name='request.Request().add_header()' id='...'>1778>>> req.add_header.assret_called_with1779Traceback (most recent call last):1780 ...1781AttributeError: Mock object has no attribute 'assret_called_with'1782>>> req.add_header.assert_called_with('spam', 'eggs')1783```17841785Во многих случаях достаточно просто добавить `autospec=True` к существующим вызовам [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch), и это защитит от ошибок, вызванных опечатками и изменениями API.17861787Помимо использования *autospec* через [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) существует [`create_autospec()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.create_autospec) для непосредственного создания моков с авто-спецификацией:17881789```python1790>>> from urllib import request1791>>> mock_request = create_autospec(request)1792>>> mock_request.Request('foo', 'bar')1793<NonCallableMagicMock name='mock.Request()' spec='Request' id='...'>1794```17951796Однако у этого подхода есть оговорки и ограничения, поэтому он не используется по умолчанию. Чтобы узнать, какие атрибуты доступны у объекта спецификации, autospec должен интроспектировать (получать доступ к атрибутам) спецификацию. Когда вы обращаетесь к атрибутам мока, под капотом происходит аналогичный обход оригинального объекта. Если у каких-то из ваших специфицированных объектов есть свойства или дескрипторы, которые могут запускать выполнение кода, то использовать autospec может не получиться. С другой стороны, гораздо лучше проектировать объекты так, чтобы интроспекция была безопасной [\[4\]](https://python-all.ru/3.4/library/unittest.mock.html#id10).17971798Более серьёзная проблема заключается в том, что атрибуты экземпляров часто создаются в методе [`__init__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__init__) и вообще не существуют в классе. *autospec* не может знать о динамически создаваемых атрибутах и ограничивает API видимыми атрибутами.17991800```python1801>>> class Something:1802... def __init__(self):1803... self.a = 331804...1805>>> with patch('__main__.Something', autospec=True):1806... thing = Something()1807... thing.a1808...1809Traceback (most recent call last):1810 ...1811AttributeError: Mock object has no attribute 'a'1812```18131814Существует несколько способов решить эту проблему. Самый простой (хотя и не обязательно наименее раздражающий) – просто установить нужные атрибуты на моке после его создания. То, что *autospec* не позволяет получать атрибуты, которых нет в спецификации, не мешает вам их устанавливать:18151816```python1817>>> with patch('__main__.Something', autospec=True):1818... thing = Something()1819... thing.a = 331820...1821```18221823Существует более строгая версия как *spec*, так и *autospec*, которая *не позволяет* устанавливать несуществующие атрибуты. Это полезно, если вы хотите гарантировать, что ваш код *устанавливает* только допустимые атрибуты, но, очевидно, это блокирует данный конкретный сценарий:18241825```python1826>>> with patch('__main__.Something', autospec=True, spec_set=True):1827... thing = Something()1828... thing.a = 331829...1830Traceback (most recent call last):1831 ...1832AttributeError: Mock object has no attribute 'a'1833```18341835Вероятно, лучший способ решения проблемы – добавить атрибуты класса в качестве значений по умолчанию для членов экземпляра, инициализируемых в [`__init__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__init__). Обратите внимание, что если устанавливаются только атрибуты по умолчанию в [`__init__()`](https://python-all.ru/3.4/reference/datamodel.html#object.__init__), то их указание через атрибуты класса (разделяемые между экземплярами, конечно) также быстрее. Например:18361837```python1838class Something:1839 a = 331840```18411842Это поднимает ещё одну проблему. Довольно часто указывают значение по умолчанию `None` для членов, которые позже будут объектом другого типа. `None` бесполезен в качестве спецификации, потому что не позволит обращаться *ни к каким* атрибутам или методам. Поскольку `None` *никогда* не будет полезен как спецификация и, вероятно, указывает на член, который обычно будет другого типа, autospec не использует спецификацию для членов, установленных в `None`. Они будут просто обычными моками (точнее, MagicMock):18431844```python1845>>> class Something:1846... member = None1847...1848>>> mock = create_autospec(Something)1849>>> mock.member.foo.bar.baz()1850<MagicMock name='mock.member.foo.bar.baz()' id='...'>1851```18521853Если изменение ваших рабочих классов для добавления значений по умолчанию не подходит, то есть другие варианты. Один из них – просто использовать экземпляр в качестве спецификации вместо класса. Другой – создать подкласс рабочего класса и добавить значения по умолчанию в подкласс, не затрагивая рабочий класс. Оба варианта требуют использования альтернативного объекта в качестве спецификации. К счастью, [`patch()`](https://python-all.ru/3.4/library/unittest.mock.html#unittest.mock.patch) это поддерживает: можно просто передать альтернативный объект в качестве аргумента *autospec*:18541855```python1856>>> class Something:1857... def __init__(self):1858... self.a = 331859...1860>>> class SomethingForTest(Something):1861... a = 331862...1863>>> p = patch('__main__.Something', autospec=SomethingForTest)1864>>> mock = p.start()1865>>> mock.a1866<NonCallableMagicMock name='Something.a' spec='int' id='...'>1867```18681869| [\[4\]](https://python-all.ru/3.4/library/unittest.mock.html#id9) | Это относится только к классам или уже созданным объектам. Вызов имитированного класса для создания имитированного экземпляра *не* создаёт реальный экземпляр. Выполняются только поиски атрибутов, а также вызовы [`dir()`](https://python-all.ru/3.4/library/functions.html#dir). |1870| --- | --- |1871