Документация Python неофициальный перевод

unittest.mock.md

2498 строк · 157.3 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.15/library/unittest.mock.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `unittest.mock` – библиотека mock-объектов89Добавлено в версии 3.3.1011**Исходный код:** [Lib/unittest/mock.py](https://python-all.ru/src/3.15/Lib/unittest/mock.py)1213---1415`unittest.mock` – это библиотека для тестирования в Python. Она позволяет заменять части тестируемой системы mock-объектами и делать утверждения о том, как они были использованы.1617`unittest.mock` предоставляет базовый класс [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), устраняя необходимость создания множества заглушек во всём наборе тестов. После выполнения действия можно делать утверждения о том, какие методы/атрибуты использовались и с какими аргументами они были вызваны. Также можно задавать возвращаемые значения и устанавливать нужные атрибуты обычным способом.1819Кроме того, mock предоставляет декоратор [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch), который обрабатывает подмену атрибутов модуля и класса в рамках теста, а также [`sentinel`](https://python-all.ru/3.15/library/functions.html#sentinel) для создания уникальных объектов. Смотрите [краткое руководство](https://python-all.ru/3.15/library/unittest.mock.html#quick-guide) для примеров использования [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) и `patch()`.2021Mock разработан для использования с [`unittest`](https://python-all.ru/3.15/library/unittest.html#module-unittest) и основан на шаблоне «действие -\> утверждение» вместо «запись -\> воспроизведение», используемого многими фреймворками для имитации.2223Существует обратный порт `unittest.mock` для более старых версий Python, доступный как [mock](https://python-all.ru/3.15/library/unittest.mock.html) на PyPI.2425## Краткое руководство2627Объекты [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) и [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) создают все атрибуты и методы по мере обращения к ним и сохраняют сведения о том, как они использовались. Можно настраивать их, задавая возвращаемые значения или ограничивая доступные атрибуты, а затем делать утверждения о том, как они были использованы:2829```python30>>> from unittest.mock import MagicMock31>>> thing = ProductionClass()32>>> thing.method = MagicMock(return_value=3)33>>> thing.method(3, 4, 5, key='value')34335>>> thing.method.assert_called_with(3, 4, 5, key='value')36```3738[`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) позволяет выполнять побочные эффекты, в том числе вызывать исключение при вызове mock-объекта:3940```python41>>> from unittest.mock import Mock42>>> mock = Mock(side_effect=KeyError('foo'))43>>> mock()44Traceback (most recent call last):45 ...46KeyError: 'foo'47```4849```python50>>> values = {'a': 1, 'b': 2, 'c': 3}51>>> def side_effect(arg):52...     return values[arg]53...54>>> mock.side_effect = side_effect55>>> mock('a'), mock('b'), mock('c')56(1, 2, 3)57>>> mock.side_effect = [5, 4, 3, 2, 1]58>>> mock(), mock(), mock()59(5, 4, 3)60```6162У Mock есть много других способов настройки и управления его поведением. Например, аргумент *spec* настраивает mock так, чтобы он брал свою спецификацию из другого объекта. Попытка обратиться к атрибутам или методам mock, которые отсутствуют в спецификации, приведёт к ошибке [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).6364Декоратор/контекстный менеджер [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) упрощает имитацию классов или объектов в тестируемом модуле. Указанный объект заменяется mock-объектом (или другим объектом) во время теста и восстанавливается после его завершения:6566```python67>>> from unittest.mock import patch68>>> @patch('module.ClassName2')69... @patch('module.ClassName1')70... def test(MockClass1, MockClass2):71...     module.ClassName1()72...     module.ClassName2()73...     assert MockClass1 is module.ClassName174...     assert MockClass2 is module.ClassName275...     assert MockClass1.called76...     assert MockClass2.called77...78>>> test()79```8081> **Примечание**82>83> При вложении декораторов patch моки передаются в декорированную функцию в том же порядке, в котором они применяются (обычный порядок применения декораторов в *Python*). Это означает снизу вверх, поэтому в примере выше mock для `module.ClassName1` передаётся первым.84>85> Для [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) важно, что подменяются объекты в том пространстве имён, где они ищутся. Обычно это понятно, но для быстрого ознакомления прочтите [где делать подмену](https://python-all.ru/3.15/library/unittest.mock.html#where-to-patch).8687Помимо использования в качестве декоратора, [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) можно использовать как контекстный менеджер в операторе with:8889```python90>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:91...     thing = ProductionClass()92...     thing.method(1, 2, 3)93...94>>> mock_method.assert_called_once_with(1, 2, 3)95```9697Также есть [`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) для установки значений в словаре только в пределах области видимости и восстановления словаря в исходное состояние после завершения теста:9899```python100>>> foo = {'key': 'value'}101>>> original = foo.copy()102>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):103...     assert foo == {'newkey': 'newvalue'}104...105>>> assert foo == original106```107108Mock поддерживает имитацию [магических методов](https://python-all.ru/3.15/library/unittest.mock.html#magic-methods) Python. Самый простой способ использования магических методов – это класс [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock). Он позволяет делать такие вещи, как:109110```python111>>> mock = MagicMock()112>>> mock.__str__.return_value = 'foobarbaz'113>>> str(mock)114'foobarbaz'115>>> mock.__str__.assert_called_with()116```117118Mock позволяет назначать функции (или другие экземпляры Mock) магическим методам, и они будут вызываться должным образом. Класс [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) – это просто разновидность Mock, в которой все магические методы уже предсозданы (ну, по крайней мере, все полезные).119120Далее приведён пример использования магических методов с обычным классом Mock:121122```python123>>> mock = Mock()124>>> mock.__str__ = Mock(return_value='wheeeeee')125>>> str(mock)126'wheeeeee'127```128129Чтобы объекты-заглушки в тестах имели тот же API, что и заменяемые объекты, можно воспользоваться [автоспецификацией](https://python-all.ru/3.15/library/unittest.mock.html#auto-speccing). Автоспецификацию можно выполнить через аргумент *autospec* функции patch или через функцию [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec). Автоспецификация создаёт объекты-заглушки с теми же атрибутами и методами, что и заменяемые объекты, а все функции и методы (включая конструкторы) имеют ту же сигнатуру вызова, что и настоящий объект.130131Благодаря этому заглушки будут вести себя так же, как рабочий код, если их использовать неправильно:132133```python134>>> from unittest.mock import create_autospec135>>> def function(a, b, c):136...     pass137...138>>> mock_function = create_autospec(function, return_value='fishy')139>>> mock_function(1, 2, 3)140'fishy'141>>> mock_function.assert_called_once_with(1, 2, 3)142>>> mock_function('wrong arguments')143Traceback (most recent call last):144 ...145TypeError: missing a required argument: 'b'146```147148[`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec) также можно применять к классам – тогда копируется сигнатура метода `__init__`, и к вызываемым объектам – копируется сигнатура метода `__call__`.149150## Класс Mock151152[`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) – это гибкий объект-заглушка, предназначенный для замены заглушек и тестовых дублёров по всему коду. Заглушки вызываемы и при обращении [\[1\]](https://python-all.ru/3.15/library/unittest.mock.html#id3) создают атрибуты как новые заглушки. Обращение к одному и тому же атрибуту всегда возвращает одну и ту же заглушку. Заглушки записывают, как вы их используете, что позволяет делать утверждения о том, что ваш код с ними сделал.153154[`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) – это подкласс [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), в котором все магические методы уже предопределены и готовы к использованию. Существуют также невызываемые варианты, полезные, когда нужно подменить объекты, которые не вызываются: [`NonCallableMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.NonCallableMock) и [`NonCallableMagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.NonCallableMagicMock).155156Декораторы [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) упрощают временную замену классов в конкретном модуле объектом [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock). По умолчанию `patch()` создаёт для вас [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock). Можно указать альтернативный класс для `Mock` с помощью аргумента *new\_callable* функции `patch()`.157158#### `class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)`159160Создаёт новый объект `Mock`. `Mock` принимает несколько необязательных аргументов, задающих поведение объекта Mock:161162- *spec*: может быть списком строк или существующим объектом (классом или экземпляром), который служит спецификацией для объекта-заглушки. Если передать объект, список строк формируется вызовом dir у этого объекта (исключая неподдерживаемые магические атрибуты и методы). Обращение к атрибуту, отсутствующему в этом списке, вызовет исключение [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).163164  Если *spec* – объект (а не список строк), то [`__class__`](https://python-all.ru/3.15/reference/datamodel.html#object.__class__) возвращает класс этого объекта-спецификации. Это позволяет заглушкам проходить проверки [`isinstance()`](https://python-all.ru/3.15/library/functions.html#isinstance).165- *spec\_set*: более строгий вариант *spec*. Если он указан, попытка *установить* или прочитать у заглушки атрибут, отсутствующий у объекта, переданного как *spec\_set*, вызовет [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).166- *side\_effect*: функция, вызываемая каждый раз при вызове Mock. См. атрибут [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect). Полезна для возбуждения исключений или динамического изменения возвращаемых значений. Функция вызывается с теми же аргументами, что и заглушка, и если она не возвращает [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT), то возвращаемое значение этой функции становится возвращаемым значением заглушки.167168  Альтернативно *side\_effect* может быть классом исключения или экземпляром. В этом случае исключение будет возбуждено при вызове заглушки.169170  Если *side\_effect* является итерируемым, то каждый вызов заглушки будет возвращать следующее значение из итерируемого.171172  *side\_effect* можно очистить, установив его равным `None`.173- *return\_value*: значение, возвращаемое при вызове заглушки. По умолчанию это новый Mock (создаётся при первом обращении). См. атрибут [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value).174- *unsafe*: по умолчанию обращение к любому атрибуту, имя которого начинается с *assert*, *assret*, *asert*, *aseert* или *assrt*, вызовет исключение [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError). Передача `unsafe=True` разрешит доступ к этим атрибутам.175176  Добавлено в версии 3.5.177- *wraps*: объект, который будет обёрнут заглушкой. Если *wraps* не равен `None`, то вызов Mock передаётся обёрнутому объекту (возвращается реальный результат). Обращение к атрибуту заглушки возвращает объект Mock, который оборачивает соответствующий атрибут обёрнутого объекта (попытка обратиться к несуществующему атрибуту вызовет [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError)).178179  Если для заглушки явно задан *return\_value*, то вызовы не передаются обёрнутому объекту, а возвращается значение *return\_value*.180- *name*: если у заглушки есть имя, оно будет использоваться в repr заглушки. Это может быть полезно для отладки. Имя распространяется на дочерние заглушки.181182Заглушки также можно вызывать с произвольными именованными аргументами. Они будут использованы для установки атрибутов заглушки после её создания. Подробнее см. метод [`configure_mock()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.configure_mock).183184#### `assert_called()`185186Утверждает, что заглушка вызывалась хотя бы один раз.187188```python189>>> mock = Mock()190>>> mock.method()191<Mock name='mock.method()' id='...'>192>>> mock.method.assert_called()193```194195Добавлено в версии 3.6.196197#### `assert_called_once()`198199Утверждает, что заглушка вызывалась ровно один раз.200201```python202>>> mock = Mock()203>>> mock.method()204<Mock name='mock.method()' id='...'>205>>> mock.method.assert_called_once()206>>> mock.method()207<Mock name='mock.method()' id='...'>208>>> mock.method.assert_called_once()209Traceback (most recent call last):210...211AssertionError: Expected 'method' to have been called once. Called 2 times.212Calls: [call(), call()].213```214215Добавлено в версии 3.6.216217#### `assert_called_with(*args, **kwargs)`218219Этот метод – удобный способ утверждать, что последний вызов был сделан определённым образом:220221```python222>>> mock = Mock()223>>> mock.method(1, 2, 3, test='wow')224<Mock name='mock.method()' id='...'>225>>> mock.method.assert_called_with(1, 2, 3, test='wow')226```227228#### `assert_called_once_with(*args, **kwargs)`229230Утверждает, что заглушка вызывалась ровно один раз, и этот вызов был с указанными аргументами.231232```python233>>> mock = Mock(return_value=None)234>>> mock('foo', bar='baz')235>>> mock.assert_called_once_with('foo', bar='baz')236>>> mock('other', bar='values')237>>> mock.assert_called_once_with('other', bar='values')238Traceback (most recent call last):239  ...240AssertionError: Expected 'mock' to be called once. Called 2 times.241Calls: [call('foo', bar='baz'), call('other', bar='values')].242```243244#### `assert_any_call(*args, **kwargs)`245246Утверждает, что mock был вызван с указанными аргументами.247248Утверждение проходит, если макет *когда-либо* вызывался, в отличие от [`assert_called_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_with) и [`assert_called_once_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with), которые проходят только в том случае, если вызов является самым последним, а в случае `assert_called_once_with()` он также должен быть единственным вызовом.249250```python251>>> mock = Mock(return_value=None)252>>> mock(1, 2, arg='thing')253>>> mock('some', 'thing', 'else')254>>> mock.assert_any_call(1, 2, arg='thing')255```256257#### `assert_has_calls(calls, any_order=False)`258259Утверждает, что mock был вызван с указанными вызовами. Список [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) проверяется на наличие этих вызовов.260261Если *any\_order* имеет значение false, то вызовы должны быть последовательными. Допускаются дополнительные вызовы до или после указанных вызовов.262263Если *any\_order* имеет значение true, то вызовы могут быть в любом порядке, но все они должны присутствовать в [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls).264265```python266>>> mock = Mock(return_value=None)267>>> mock(1)268>>> mock(2)269>>> mock(3)270>>> mock(4)271>>> calls = [call(2), call(3)]272>>> mock.assert_has_calls(calls)273>>> calls = [call(4), call(2), call(3)]274>>> mock.assert_has_calls(calls, any_order=True)275```276277#### `assert_not_called()`278279Утверждает, что макет никогда не вызывался.280281```python282>>> m = Mock()283>>> m.hello.assert_not_called()284>>> obj = m.hello()285>>> m.hello.assert_not_called()286Traceback (most recent call last):287  ...288AssertionError: Expected 'hello' to not have been called. Called 1 times.289Calls: [call()].290```291292Добавлено в версии 3.5.293294#### `reset_mock(*, return_value=False, side_effect=False)`295296Метод reset\_mock сбрасывает все атрибуты вызовов у макета:297298```pycon299>>> mock = Mock(return_value=None)300>>> mock('hello')301>>> mock.called302True303>>> mock.reset_mock()304>>> mock.called305False306```307308Это может быть полезно, когда нужно выполнить серию утверждений, повторно использующих один и тот же объект.309310Параметр *return\_value* при установке в `True` сбрасывает [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value):311312```pycon313>>> mock = Mock(return_value=5)314>>> mock('hello')3155316>>> mock.reset_mock(return_value=True)317>>> mock('hello')318<Mock name='mock()' id='...'>319```320321Параметр *side\_effect* при установке в `True` сбрасывает [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect):322323```pycon324>>> mock = Mock(side_effect=ValueError)325>>> mock('hello')326Traceback (most recent call last):327  ...328ValueError329>>> mock.reset_mock(side_effect=True)330>>> mock('hello')331<Mock name='mock()' id='...'>332```333334Обратите внимание, что `reset_mock()` *не* очищает [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value), [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) или любые дочерние атрибуты, которые были установлены с помощью обычного присваивания по умолчанию.335336Дочерние макеты также сбрасываются.337338Изменено в версии 3.6: Добавлены два аргумента, передаваемых только по ключу, в функцию reset\_mock.339340#### `mock_add_spec(spec, spec_set=False)`341342Добавляет спецификацию к макету. *spec* может быть объектом или списком строк. Только атрибуты, указанные в *spec*, можно получить как атрибуты макета.343344Если *spec\_set* имеет значение true, то можно устанавливать только атрибуты, указанные в спецификации.345346#### `attach_mock(mock, attribute)`347348Прикрепляет макет как атрибут к текущему, заменяя его имя и родителя. Вызовы прикреплённого макета будут записаны в атрибуты [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) текущего макета.349350#### `configure_mock(**kwargs)`351352Устанавливает атрибуты макета через именованные аргументы.353354Атрибуты, возвращаемые значения и побочные эффекты могут быть установлены на дочерних макетах с помощью стандартной точечной нотации и распаковки словаря в вызове метода:355356```python357>>> mock = Mock()358>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}359>>> mock.configure_mock(**attrs)360>>> mock.method()3613362>>> mock.other()363Traceback (most recent call last):364  ...365KeyError366```367368То же самое можно сделать в вызове конструктора макетов:369370```python371>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}372>>> mock = Mock(some_attribute='eggs', **attrs)373>>> mock.some_attribute374'eggs'375>>> mock.method()3763377>>> mock.other()378Traceback (most recent call last):379  ...380KeyError381```382383`configure_mock()` существует для упрощения настройки после создания макета.384385#### `__dir__()`386387Объекты `Mock` ограничивают результаты `dir(some_mock)` полезными результатами. Для макетов с *spec* сюда входят все разрешённые атрибуты макета.388389Смотрите [`FILTER_DIR`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.FILTER_DIR) о том, что делает эта фильтрация и как её отключить.390391#### `_get_child_mock(**kw)`392393Создаёт дочерние макеты для атрибутов и возвращаемого значения. По умолчанию дочерние макеты будут того же типа, что и родительский. Подклассы Mock могут переопределить это для настройки способа создания дочерних макетов.394395Для невызываемых макетов будет использоваться вызываемый вариант (а не пользовательский подкласс).396397#### `called`398399Логическое значение, указывающее, был ли вызван mock-объект:400401```python402>>> mock = Mock(return_value=None)403>>> mock.called404False405>>> mock()406>>> mock.called407True408```409410#### `call_count`411412Целое число, показывающее, сколько раз был вызван mock-объект:413414```python415>>> mock = Mock(return_value=None)416>>> mock.call_count4170418>>> mock()419>>> mock()420>>> mock.call_count4212422```423424#### `return_value`425426Установите это, чтобы настроить значение, возвращаемое при вызове mock:427428```python429>>> mock = Mock()430>>> mock.return_value = 'fish'431>>> mock()432'fish'433```434435Значение по умолчанию – это mock-объект, и его можно настроить обычным способом:436437```python438>>> mock = Mock()439>>> mock.return_value.attribute = sentinel.Attribute440>>> mock.return_value()441<Mock name='mock()()' id='...'>442>>> mock.return_value.assert_called_with()443```444445[`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) также можно установить в конструкторе:446447```python448>>> mock = Mock(return_value=3)449>>> mock.return_value4503451>>> mock()4523453```454455#### `side_effect`456457Это может быть функция, вызываемая при вызове mock-объекта, итерируемый объект или исключение (класс или экземпляр), которое должно быть возбуждено.458459Если передать функцию, она будет вызвана с теми же аргументами, что и mock, и, если функция не возвращает синглтон [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT), вызов mock вернёт результат функции. Если функция возвращает `DEFAULT`, то mock вернёт своё обычное значение (из [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value)).460461Если передать итерируемый объект, он используется для получения итератора, который должен возвращать значение при каждом вызове. Это значение может быть либо экземпляром исключения для возбуждения, либо значением, возвращаемым из вызова mock (обработка [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT) идентична случаю с функцией).462463Пример mock-объекта, возбуждающего исключение (для проверки обработки исключений API):464465```python466>>> mock = Mock()467>>> mock.side_effect = Exception('Boom!')468>>> mock()469Traceback (most recent call last):470  ...471Exception: Boom!472```473474Использование [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) для возврата последовательности значений:475476```python477>>> mock = Mock()478>>> mock.side_effect = [3, 2, 1]479>>> mock(), mock(), mock()480(3, 2, 1)481```482483Использование вызываемого объекта:484485```python486>>> mock = Mock(return_value=3)487>>> def side_effect(*args, **kwargs):488...     return DEFAULT489...490>>> mock.side_effect = side_effect491>>> mock()4923493```494495[`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) можно установить в конструкторе. Вот пример, который добавляет единицу к значению, с которым вызывается mock, и возвращает результат:496497```python498>>> side_effect = lambda value: value + 1499>>> mock = Mock(side_effect=side_effect)500>>> mock(3)5014502>>> mock(-8)503-7504```505506Установка [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) в `None` очищает его:507508```python509>>> m = Mock(side_effect=KeyError, return_value=3)510>>> m()511Traceback (most recent call last):512 ...513KeyError514>>> m.side_effect = None515>>> m()5163517```518519#### `call_args`520521Это либо `None` (если mock не вызывался), либо аргументы, с которыми mock вызывался в последний раз. Это будет кортеж: первый элемент, который также доступен через свойство `args`, – это позиционные аргументы, с которыми был вызван mock (или пустой кортеж), а второй элемент, доступный через свойство `kwargs`, – это именованные аргументы (или пустой словарь).522523```python524>>> mock = Mock(return_value=None)525>>> print(mock.call_args)526None527>>> mock()528>>> mock.call_args529call()530>>> mock.call_args == ()531True532>>> mock(3, 4)533>>> mock.call_args534call(3, 4)535>>> mock.call_args == ((3, 4),)536True537>>> mock.call_args.args538(3, 4)539>>> mock.call_args.kwargs540{}541>>> mock(3, 4, 5, key='fish', next='w00t!')542>>> mock.call_args543call(3, 4, 5, key='fish', next='w00t!')544>>> mock.call_args.args545(3, 4, 5)546>>> mock.call_args.kwargs547{'key': 'fish', 'next': 'w00t!'}548```549550[`call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args), а также элементы списков [`call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list), [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) являются объектами [`call`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call). Это кортежи, поэтому их можно распаковать для получения отдельных аргументов и создания более сложных утверждений. См. [вызовы как кортежи](https://python-all.ru/3.15/library/unittest.mock.html#calls-as-tuples).551552Изменено в версии 3.8: Добавлены свойства `args` и `kwargs`.553554#### `call_args_list`555556Это список всех вызовов mock-объекта в порядке их выполнения (поэтому длина списка равна количеству вызовов). До любых вызовов это пустой список. Объект [`call`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call) можно использовать для удобного создания списков вызовов для сравнения с [`call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list).557558```python559>>> mock = Mock(return_value=None)560>>> mock()561>>> mock(3, 4)562>>> mock(key='fish', next='w00t!')563>>> mock.call_args_list564[call(), call(3, 4), call(key='fish', next='w00t!')]565>>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)]566>>> mock.call_args_list == expected567True568```569570Элементы [`call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list) являются объектами [`call`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [вызовы как кортежи](https://python-all.ru/3.15/library/unittest.mock.html#calls-as-tuples).571572#### `method_calls`573574Помимо отслеживания собственных вызовов, mock-объекты также отслеживают вызовы методов и атрибутов, а также *их* методов и атрибутов:575576```python577>>> mock = Mock()578>>> mock.method()579<Mock name='mock.method()' id='...'>580>>> mock.property.method.attribute()581<Mock name='mock.property.method.attribute()' id='...'>582>>> mock.method_calls583[call.method(), call.property.method.attribute()]584```585586Элементы [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls) являются объектами [`call`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [вызовы как кортежи](https://python-all.ru/3.15/library/unittest.mock.html#calls-as-tuples).587588#### `mock_calls`589590[`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) записывает *все* вызовы mock-объекта, его методов, магических методов *и* mock-объектов возвращаемых значений.591592```python593>>> mock = MagicMock()594>>> result = mock(1, 2, 3)595>>> mock.first(a=3)596<MagicMock name='mock.first()' id='...'>597>>> mock.second()598<MagicMock name='mock.second()' id='...'>599>>> int(mock)6001601>>> result(1)602<MagicMock name='mock()()' id='...'>603>>> expected = [call(1, 2, 3), call.first(a=3), call.second(),604... call.__int__(), call()(1)]605>>> mock.mock_calls == expected606True607```608609Элементы [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) являются объектами [`call`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call). Их можно распаковать как кортежи для получения отдельных аргументов. См. [вызовы как кортежи](https://python-all.ru/3.15/library/unittest.mock.html#calls-as-tuples).610611> **Примечание**612>613> Способ записи [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) означает, что при вложенных вызовах параметры вышестоящих вызовов не записываются и поэтому всегда будут сравниваться как равные:614>615> ```python616> >>> mock = MagicMock()617> >>> mock.top(a=3).bottom()618> <MagicMock name='mock.top().bottom()' id='...'>619> >>> mock.mock_calls620> [call.top(a=3), call.top().bottom()]621> >>> mock.mock_calls[-1] == call.top(a=-1).bottom()622> True623> ```624625#### `__class__`626627Обычно атрибут `__class__` объекта возвращает его тип. Для mock-объекта с `spec`, `__class__` вместо этого возвращает класс спецификации. Это позволяет mock-объектам проходить тесты [`isinstance()`](https://python-all.ru/3.15/library/functions.html#isinstance) для объекта, который они заменяют или под который маскируются:628629```python630>>> mock = Mock(spec=3)631>>> isinstance(mock, int)632True633```634635`__class__` может быть присвоен, что позволяет mock пройти проверку [`isinstance()`](https://python-all.ru/3.15/library/functions.html#isinstance) без необходимости указывать spec:636637```python638>>> mock = Mock()639>>> mock.__class__ = dict640>>> isinstance(mock, dict)641True642```643644#### `class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, **kwargs)`645646Невызываемая версия [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock). Параметры конструктора имеют тот же смысл, что и в `Mock`, за исключением *return\_value* и *side\_effect*, которые не имеют смысла для невызываемого mock.647648Объекты mock, использующие класс или экземпляр в качестве `spec` или `spec_set`, способны проходить тесты [`isinstance()`](https://python-all.ru/3.15/library/functions.html#isinstance):649650```python651>>> mock = Mock(spec=SomeClass)652>>> isinstance(mock, SomeClass)653True654>>> mock = Mock(spec_set=SomeClass())655>>> isinstance(mock, SomeClass)656True657```658659Классы [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) поддерживают имитацию магических методов. Подробнее см. [магические методы](https://python-all.ru/3.15/library/unittest.mock.html#magic-methods).660661Классы mock и декораторы [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) принимают произвольные именованные аргументы для настройки. Для декораторов `patch()` именованные аргументы передаются конструктору создаваемого mock. Именованные аргументы предназначены для настройки атрибутов mock:662663```python664>>> m = MagicMock(attribute=3, other='fish')665>>> m.attribute6663667>>> m.other668'fish'669```670671Возвращаемое значение и побочный эффект дочерних mock-объектов можно установить таким же образом, используя точечную нотацию. Поскольку точечные имена нельзя использовать непосредственно в вызове, необходимо создать словарь и распаковать его с помощью `**`:672673```python674>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}675>>> mock = Mock(some_attribute='eggs', **attrs)676>>> mock.some_attribute677'eggs'678>>> mock.method()6793680>>> mock.other()681Traceback (most recent call last):682  ...683KeyError684```685686Вызываемый mock, созданный с *spec* (или *spec\_set*), будет анализировать сигнатуру объекта спецификации при сопоставлении вызовов с mock. Следовательно, он может сопоставлять аргументы фактического вызова независимо от того, переданы они позиционно или по имени:687688```python689>>> def f(a, b, c): pass690...691>>> mock = Mock(spec=f)692>>> mock(1, 2, c=3)693<Mock name='mock()' id='140161580456576'>694>>> mock.assert_called_with(1, 2, 3)695>>> mock.assert_called_with(a=1, b=2, c=3)696```697698Это относится к [`assert_called_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_with), [`assert_called_once_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with), [`assert_has_calls()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls) и [`assert_any_call()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_any_call). При [автоспецификации](https://python-all.ru/3.15/library/unittest.mock.html#auto-speccing) это также будет применяться к вызовам методов объекта mock.699700Изменено в версии 3.4: Добавлен анализ сигнатуры для объектов mock с указанной спецификацией и автоспецификацией.701702#### `class unittest.mock.PropertyMock(*args, **kwargs)`703704Mock, предназначенный для использования в качестве [`property`](https://python-all.ru/3.15/library/functions.html#property) или другого [дескриптора](https://python-all.ru/3.15/glossary.html#term-descriptor) в классе. `PropertyMock` предоставляет методы [`__get__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__get__) и [`__set__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__set__), чтобы можно было указать возвращаемое значение при его получении.705706Получение экземпляра `PropertyMock` из объекта вызывает mock без аргументов. Установка его вызывает mock с устанавливаемым значением.707708```python709>>> class Foo:710...     @property711...     def foo(self):712...         return 'something'713...     @foo.setter714...     def foo(self, value):715...         pass716...717>>> with patch('__main__.Foo.foo', new_callable=PropertyMock) as mock_foo:718...     mock_foo.return_value = 'mockity-mock'719...     this_foo = Foo()720...     print(this_foo.foo)721...     this_foo.foo = 6722...723mockity-mock724>>> mock_foo.mock_calls725[call(), call(6)]726```727728Из-за способа хранения атрибутов mock нельзя напрямую прикрепить [`PropertyMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.PropertyMock) к объекту mock. Вместо этого можно прикрепить его к объекту типа mock:729730```python731>>> m = MagicMock()732>>> p = PropertyMock(return_value=3)733>>> type(m).foo = p734>>> m.foo7353736>>> p.assert_called_once_with()737```738739> **Внимание**740>741> Если [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError) возбуждается [`PropertyMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.PropertyMock), это будет интерпретироваться как отсутствующий дескриптор, и [`__getattr__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__getattr__) будет вызван на родительском mock:742>743> ```python744> >>> m = MagicMock()745> >>> no_attribute = PropertyMock(side_effect=AttributeError)746> >>> type(m).my_property = no_attribute747> >>> m.my_property748> <MagicMock name='mock.my_property' id='140165240345424'>749> ```750>751> Подробнее см. [`__getattr__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__getattr__).752753#### `class unittest.mock.AsyncMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)`754755Асинхронная версия [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock). Объект `AsyncMock` будет вести себя так, что объект будет распознаваться как асинхронная функция, а результат вызова будет ожидаемым объектом.756757```python758>>> mock = AsyncMock()759>>> inspect.iscoroutinefunction(mock)760True761>>> inspect.isawaitable(mock())762True763```764765Результат `mock()` – это асинхронная функция, которая будет иметь результат `side_effect` или `return_value` после ожидания:766767- если `side_effect` – это функция, асинхронная функция вернет результат этой функции,768- если `side_effect` – это исключение, асинхронная функция возбудит это исключение,769- если `side_effect` – это итерируемый объект, асинхронная функция вернет следующее значение из итерируемого объекта; однако, если последовательность результатов исчерпана, `StopAsyncIteration` возбуждается немедленно,770- если `side_effect` не определен, асинхронная функция вернет значение, определенное `return_value`; следовательно, по умолчанию асинхронная функция возвращает новый объект `AsyncMock`.771772Установка *spec* для [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) или [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) в асинхронную функцию приведет к тому, что после вызова будет возвращен объект корутины.773774```python775>>> async def async_func(): pass776...777>>> mock = MagicMock(async_func)778>>> mock779<MagicMock spec='function' id='...'>780>>> mock()781<coroutine object AsyncMockMixin._mock_call at ...>782```783784Установка *spec* для [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) или `AsyncMock` в класс с асинхронными и синхронными функциями автоматически определит синхронные функции и установит их как `MagicMock` (если родительский mock является `AsyncMock` или `MagicMock`) или `Mock` (если родительский mock является `Mock`). Все асинхронные функции будут `AsyncMock`.785786```python787>>> class ExampleClass:788...     def sync_foo():789...         pass790...     async def async_foo():791...         pass792...793>>> a_mock = AsyncMock(ExampleClass)794>>> a_mock.sync_foo795<MagicMock name='mock.sync_foo' id='...'>796>>> a_mock.async_foo797<AsyncMock name='mock.async_foo' id='...'>798>>> mock = Mock(ExampleClass)799>>> mock.sync_foo800<Mock name='mock.sync_foo' id='...'>801>>> mock.async_foo802<AsyncMock name='mock.async_foo' id='...'>803```804805Добавлено в версии 3.8.806807#### `assert_awaited()`808809Утверждает, что mock был ожидан хотя бы один раз. Обратите внимание, что это отделено от вызова объекта, необходимо использовать ключевое слово `await`:810811```python812>>> mock = AsyncMock()813>>> async def main(coroutine_mock):814...     await coroutine_mock815...816>>> coroutine_mock = mock()817>>> mock.called818True819>>> mock.assert_awaited()820Traceback (most recent call last):821...822AssertionError: Expected mock to have been awaited.823>>> asyncio.run(main(coroutine_mock))824>>> mock.assert_awaited()825```826827#### `assert_awaited_once()`828829Утверждает, что mock был ожидан ровно один раз.830831```python832>>> mock = AsyncMock()833>>> async def main():834...     await mock()835...836>>> asyncio.run(main())837>>> mock.assert_awaited_once()838>>> asyncio.run(main())839>>> mock.assert_awaited_once()840Traceback (most recent call last):841...842AssertionError: Expected mock to have been awaited once. Awaited 2 times.843```844845#### `assert_awaited_with(*args, **kwargs)`846847Утверждает, что последнее ожидание было с указанными аргументами.848849```python850>>> mock = AsyncMock()851>>> async def main(*args, **kwargs):852...     await mock(*args, **kwargs)853...854>>> asyncio.run(main('foo', bar='bar'))855>>> mock.assert_awaited_with('foo', bar='bar')856>>> mock.assert_awaited_with('other')857Traceback (most recent call last):858...859AssertionError: expected await not found.860Expected: mock('other')861Actual: mock('foo', bar='bar')862```863864#### `assert_awaited_once_with(*args, **kwargs)`865866Утверждает, что мок был вызван через await ровно один раз и с указанными аргументами.867868```python869>>> mock = AsyncMock()870>>> async def main(*args, **kwargs):871...     await mock(*args, **kwargs)872...873>>> asyncio.run(main('foo', bar='bar'))874>>> mock.assert_awaited_once_with('foo', bar='bar')875>>> asyncio.run(main('foo', bar='bar'))876>>> mock.assert_awaited_once_with('foo', bar='bar')877Traceback (most recent call last):878...879AssertionError: Expected mock to have been awaited once. Awaited 2 times.880```881882#### `assert_any_await(*args, **kwargs)`883884Утверждает, что мок когда-либо был вызван через await с указанными аргументами.885886```python887>>> mock = AsyncMock()888>>> async def main(*args, **kwargs):889...     await mock(*args, **kwargs)890...891>>> asyncio.run(main('foo', bar='bar'))892>>> asyncio.run(main('hello'))893>>> mock.assert_any_await('foo', bar='bar')894>>> mock.assert_any_await('other')895Traceback (most recent call last):896...897AssertionError: mock('other') await not found898```899900#### `assert_has_awaits(calls, any_order=False)`901902Утверждает, что мок был вызван через await с указанными вызовами. Список [`await_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock.await_args_list) проверяется на наличие ожиданий.903904Если *any\_order* равно False, то ожидания должны быть последовательными. Дополнительные вызовы могут быть до или после указанных ожиданий.905906Если *any\_order* равно True, то ожидания могут быть в любом порядке, но все они должны присутствовать в [`await_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock.await_args_list).907908```python909>>> mock = AsyncMock()910>>> async def main(*args, **kwargs):911...     await mock(*args, **kwargs)912...913>>> calls = [call("foo"), call("bar")]914>>> mock.assert_has_awaits(calls)915Traceback (most recent call last):916...917AssertionError: Awaits not found.918Expected: [call('foo'), call('bar')]919Actual: []920>>> asyncio.run(main('foo'))921>>> asyncio.run(main('bar'))922>>> mock.assert_has_awaits(calls)923```924925#### `assert_not_awaited()`926927Утверждает, что мок никогда не вызывался через await.928929```python930>>> mock = AsyncMock()931>>> mock.assert_not_awaited()932```933934#### `reset_mock(*args, **kwargs)`935936См. [`Mock.reset_mock()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.reset_mock). Также устанавливает [`await_count`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock.await_count) в 0, [`await_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock.await_args) в None и очищает [`await_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock.await_args_list).937938#### `await_count`939940Целое число, отслеживающее, сколько раз мок-объект был вызван через await.941942```python943>>> mock = AsyncMock()944>>> async def main():945...     await mock()946...947>>> asyncio.run(main())948>>> mock.await_count9491950>>> asyncio.run(main())951>>> mock.await_count9522953```954955#### `await_args`956957Это либо `None` (если мок не был ожидан), либо аргументы, с которыми мок был вызван через await в последний раз. Работает так же, как [`Mock.call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args).958959```python960>>> mock = AsyncMock()961>>> async def main(*args):962...     await mock(*args)963...964>>> mock.await_args965>>> asyncio.run(main('foo'))966>>> mock.await_args967call('foo')968>>> asyncio.run(main('bar'))969>>> mock.await_args970call('bar')971```972973#### `await_args_list`974975Это список всех ожиданий, выполненных для мок-объекта, в порядке их поступления (таким образом, длина списка равна количеству вызовов await). Если ожиданий не было, список пуст.976977```python978>>> mock = AsyncMock()979>>> async def main(*args):980...     await mock(*args)981...982>>> mock.await_args_list983[]984>>> asyncio.run(main('foo'))985>>> mock.await_args_list986[call('foo')]987>>> asyncio.run(main('bar'))988>>> mock.await_args_list989[call('foo'), call('bar')]990```991992#### `class unittest.mock.ThreadingMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, *, timeout=UNSET, **kwargs)`993994Версия [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) для тестирования многопоточности. Объект `ThreadingMock` предоставляет дополнительные методы для ожидания вызова (вместо немедленного утверждения).995996Тайм-аут по умолчанию задаётся аргументом `timeout`, или, если он не задан, атрибутом [`ThreadingMock.DEFAULT_TIMEOUT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.ThreadingMock.DEFAULT_TIMEOUT), который по умолчанию блокирует (`None`).997998Можно настроить глобальный тайм-аут по умолчанию, задав [`ThreadingMock.DEFAULT_TIMEOUT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.ThreadingMock.DEFAULT_TIMEOUT).9991000#### `wait_until_called(*, timeout=UNSET)`10011002Ожидает, пока мок не будет вызван.10031004Если тайм-аут был передан при создании мока или если аргумент тайм-аута передан этой функции, функция вызывает исключение [`AssertionError`](https://python-all.ru/3.15/library/exceptions.html#AssertionError), если вызов не выполнен вовремя.10051006```python1007>>> mock = ThreadingMock()1008>>> thread = threading.Thread(target=mock)1009>>> thread.start()1010>>> mock.wait_until_called(timeout=1)1011>>> thread.join()1012```10131014#### `wait_until_any_call_with(*args, **kwargs)`10151016Ожидает, пока мок не будет вызван с указанными аргументами.10171018Если тайм-аут был передан при создании мока, функция вызывает [`AssertionError`](https://python-all.ru/3.15/library/exceptions.html#AssertionError), если вызов не выполнен вовремя.10191020```python1021>>> mock = ThreadingMock()1022>>> thread = threading.Thread(target=mock, args=("arg1", "arg2",), kwargs={"arg": "thing"})1023>>> thread.start()1024>>> mock.wait_until_any_call_with("arg1", "arg2", arg="thing")1025>>> thread.join()1026```10271028#### `DEFAULT_TIMEOUT`10291030Глобальный тайм-аут по умолчанию в секундах для создания экземпляров `ThreadingMock`.10311032Добавлено в версии 3.13.10331034### Вызов10351036Мок-объекты являются вызываемыми. Вызов возвращает значение, установленное как атрибут [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value). Значение по умолчанию – новый объект Mock; он создаётся при первом обращении к возвращаемому значению (явно или при вызове мока), но затем сохраняется и возвращается каждый раз.10371038Вызовы объекта будут записаны в атрибуты, такие как [`call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args) и [`call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list).10391040Если установлен [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), он будет вызван после того, как вызов будет записан, поэтому если `side_effect` вызывает исключение, вызов всё равно будет записан.10411042Самый простой способ заставить макет вызывать исключение при вызове – сделать [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) классом или экземпляром исключения:10431044```python1045>>> m = MagicMock(side_effect=IndexError)1046>>> m(1, 2, 3)1047Traceback (most recent call last):1048  ...1049IndexError1050>>> m.mock_calls1051[call(1, 2, 3)]1052>>> m.side_effect = KeyError('Bang!')1053>>> m('two', 'three', 'four')1054Traceback (most recent call last):1055  ...1056KeyError: 'Bang!'1057>>> m.mock_calls1058[call(1, 2, 3), call('two', 'three', 'four')]1059```10601061Если [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) является функцией, то вызовы макета возвращают то, что возвращает эта функция. Функция `side_effect` вызывается с теми же аргументами, что и макет. Это позволяет динамически изменять возвращаемое значение вызова в зависимости от входных данных:10621063```python1064>>> def side_effect(value):1065...     return value + 11066...1067>>> m = MagicMock(side_effect=side_effect)1068>>> m(1)106921070>>> m(2)107131072>>> m.mock_calls1073[call(1), call(2)]1074```10751076Если вы хотите, чтобы макет по-прежнему возвращал значение по умолчанию (новый макет) или любое заданное возвращаемое значение, есть два способа сделать это. Либо вернуть [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) изнутри [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), либо вернуть [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT):10771078```python1079>>> m = MagicMock()1080>>> def side_effect(*args, **kwargs):1081...     return m.return_value1082...1083>>> m.side_effect = side_effect1084>>> m.return_value = 31085>>> m()108631087>>> def side_effect(*args, **kwargs):1088...     return DEFAULT1089...1090>>> m.side_effect = side_effect1091>>> m()109231093```10941095Чтобы удалить [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) и вернуться к поведению по умолчанию, установите `side_effect` в `None`:10961097```python1098>>> m = MagicMock(return_value=6)1099>>> def side_effect(*args, **kwargs):1100...     return 31101...1102>>> m.side_effect = side_effect1103>>> m()110431105>>> m.side_effect = None1106>>> m()110761108```11091110[`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) также может быть любым итерируемым объектом. Повторные вызовы макета будут возвращать значения из итератора (пока итератор не будет исчерпан и не будет вызвано [`StopIteration`](https://python-all.ru/3.15/library/exceptions.html#StopIteration)):11111112```python1113>>> m = MagicMock(side_effect=[1, 2, 3])1114>>> m()111511116>>> m()111721118>>> m()111931120>>> m()1121Traceback (most recent call last):1122  ...1123StopIteration1124```11251126Если какие-либо элементы итератора являются исключениями, они будут вызваны вместо того, чтобы быть возвращёнными:11271128```python1129>>> iterable = (33, ValueError, 66)1130>>> m = MagicMock(side_effect=iterable)1131>>> m()1132331133>>> m()1134Traceback (most recent call last):1135 ...1136ValueError1137>>> m()1138661139```11401141### Удаление атрибутов11421143Объекты Mock создают атрибуты по запросу. Это позволяет им притворяться объектами любого типа.11441145Возможно, вы захотите, чтобы объект макета возвращал `False` при вызове [`hasattr()`](https://python-all.ru/3.15/library/functions.html#hasattr), или вызывал [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError) при получении атрибута. Это можно сделать, передав объект в качестве `spec` для макета, но это не всегда удобно.11461147Вы «блокируете» атрибуты, удаляя их. После удаления доступ к атрибуту вызовет [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).11481149```python1150>>> mock = MagicMock()1151>>> hasattr(mock, 'm')1152True1153>>> del mock.m1154>>> hasattr(mock, 'm')1155False1156>>> del mock.f1157>>> mock.f1158Traceback (most recent call last):1159    ...1160AttributeError: f1161```11621163### Имена макетов и атрибут name11641165Поскольку «name» является аргументом конструктора [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), если вы хотите, чтобы ваш объект макета имел атрибут «name», вы не можете просто передать его при создании. Есть две альтернативы. Один из вариантов – использовать [`configure_mock()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.configure_mock):11661167```python1168>>> mock = MagicMock()1169>>> mock.configure_mock(name='my_name')1170>>> mock.name1171'my_name'1172```11731174Более простой вариант – просто установить атрибут «name» после создания макета:11751176```python1177>>> mock = MagicMock()1178>>> mock.name = "foo"1179```11801181### Прикрепление макетов в качестве атрибутов11821183Когда вы прикрепляете макет как атрибут другого макета (или как возвращаемое значение), он становится «дочерним» для этого макета. Вызовы дочернего макета записываются в атрибуты [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls) и [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) родительского. Это полезно для настройки дочерних макетов и последующего их прикрепления к родительскому, или для прикрепления макетов к родительскому, который записывает все вызовы дочерних и позволяет делать утверждения о порядке вызовов между макетами:11841185```python1186>>> parent = MagicMock()1187>>> child1 = MagicMock(return_value=None)1188>>> child2 = MagicMock(return_value=None)1189>>> parent.child1 = child11190>>> parent.child2 = child21191>>> child1(1)1192>>> child2(2)1193>>> parent.mock_calls1194[call.child1(1), call.child2(2)]1195```11961197Исключение составляет случай, когда у макета есть имя. Это позволяет предотвратить «родительскую связь», если по какой-то причине вы не хотите, чтобы это происходило.11981199```python1200>>> mock = MagicMock()1201>>> not_a_child = MagicMock(name='not-a-child')1202>>> mock.attribute = not_a_child1203>>> mock.attribute()1204<MagicMock name='not-a-child()' id='...'>1205>>> mock.mock_calls1206[]1207```12081209Макеты, созданные для вас с помощью [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch), автоматически получают имена. Чтобы прикрепить макеты с именами к родительскому, используйте метод [`attach_mock()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.attach_mock) :12101211```python1212>>> thing1 = object()1213>>> thing2 = object()1214>>> parent = MagicMock()1215>>> with patch('__main__.thing1', return_value=None) as child1:1216...     with patch('__main__.thing2', return_value=None) as child2:1217...         parent.attach_mock(child1, 'child1')1218...         parent.attach_mock(child2, 'child2')1219...         child1('one')1220...         child2('two')1221...1222>>> parent.mock_calls1223[call.child1('one'), call.child2('two')]1224```12251226\[[1](https://python-all.ru/3.15/library/unittest.mock.html#id1)\]12271228Единственное исключение – это магические методы и атрибуты (те, которые имеют двойные подчёркивания в начале и конце). Mock не создаёт их, а вместо этого вызывает [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError). Это связано с тем, что интерпретатор часто неявно запрашивает эти методы и *очень* путается, получая новый объект Mock, когда ожидает магический метод. Если вам нужна поддержка магических методов, обратитесь к [магическим методам](https://python-all.ru/3.15/library/unittest.mock.html#magic-methods).12291230## Патчеры12311232Декораторы patch используются для патчинга объектов только в пределах области видимости функции, которую они декорируют. Они автоматически обрабатывают отмену патчинга, даже если возникают исключения. Все эти функции также могут использоваться в операторах with или в качестве декораторов классов.12331234### patch12351236> **Примечание**1237>1238> Ключ в том, чтобы выполнять патчинг в правильном пространстве имён. Смотрите раздел [где патчить](https://python-all.ru/3.15/library/unittest.mock.html#id6).12391240#### `unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`12411242`patch()` работает как декоратор функции, декоратор класса или контекстный менеджер. Внутри тела функции или оператора with *target* заменяется объектом *new*. Когда функция/оператор with завершается, патчинг отменяется.12431244Если *new* опущен, то цель заменяется на [`AsyncMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock), если патчируемый объект является асинхронной функцией, или на [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) в противном случае. Если `patch()` используется как декоратор и *new* опущен, созданный макет передаётся в качестве дополнительного аргумента декорируемой функции. Если `patch()` используется как контекстный менеджер, созданный макет возвращается контекстным менеджером.12451246*target* должен быть строкой в формате `'package.module.ClassName'`. *target* импортируется, и указанный объект заменяется на объект *new*, поэтому *target* должен быть импортируемым из окружения, в котором вы вызываете `patch()`. Цель импортируется при выполнении декорированной функции, а не во время декорирования.12471248Ключевые аргументы *spec* и *spec\_set* передаются в [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock), если patch создаёт его для вас.12491250Кроме того, вы можете передать `spec=True` или `spec_set=True`, что заставляет patch передать объект, который имитируется, в качестве объекта spec/spec\_set.12511252*new\_callable* позволяет указать другой класс или вызываемый объект, который будет вызван для создания объекта *new*. По умолчанию [`AsyncMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock) используется для асинхронных функций, а [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) – для остальных.12531254Более мощная форма *spec* – это *autospec*. Если установить `autospec=True`, то макет будет создан со спецификацией от заменяемого объекта. Все атрибуты макета также будут иметь спецификацию соответствующего атрибута заменяемого объекта. Методы и функции, которые имитируются, будут проверять свои аргументы и вызывать [`TypeError`](https://python-all.ru/3.15/library/exceptions.html#TypeError), если они вызываются с неправильной сигнатурой. Для макетов, заменяющих класс, их возвращаемое значение («экземпляр») будет иметь ту же спецификацию, что и класс. Смотрите функцию [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec) и [Autospeccing](https://python-all.ru/3.15/library/unittest.mock.html#auto-speccing).12551256Вместо `autospec=True` вы можете передать `autospec=some_object`, чтобы использовать произвольный объект в качестве спецификации вместо заменяемого.12571258По умолчанию `patch()` не сможет заменить атрибуты, которые не существуют. Если передать `create=True`, и атрибут не существует, patch создаст этот атрибут при вызове патченной функции и удалит его после завершения патченной функции. Это полезно для написания тестов на атрибуты, которые ваш production-код создаёт во время выполнения. По умолчанию эта возможность отключена, так как может быть опасной. Включив её, можно писать успешные тесты для API, которых на самом деле не существует!12591260> **Примечание**1261>1262> Изменено в версии 3.5: При патчинге встроенных функций в модуле не нужно передавать `create=True` – он будет добавлен по умолчанию.12631264Patch можно использовать как [`TestCase`](https://python-all.ru/3.15/library/unittest.html#unittest.TestCase) декоратор класса. Он работает путём декорирования каждого тестового метода в классе. Это уменьшает шаблонный код, когда тестовые методы используют общий набор патчей. `patch()` находит тесты, ища имена методов, начинающиеся с `patch.TEST_PREFIX`. По умолчанию это `'test'`, что соответствует тому, как [`unittest`](https://python-all.ru/3.15/library/unittest.html#module-unittest) находит тесты. Альтернативный префикс можно указать, задав `patch.TEST_PREFIX`.12651266Patch можно использовать как менеджер контекста с оператором with. В этом случае патч применяется к блоку с отступом после оператора with. Если используется «as», то патченный объект будет привязан к имени после «as»; это очень полезно, когда `patch()` создаёт мок-объект.12671268`patch()` принимает произвольные именованные аргументы. Они будут переданы в [`AsyncMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock), если патченный объект асинхронный, в противном случае в [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock), или в *new\_callable*, если он указан.12691270`patch.dict(...)`, `patch.multiple(...)` и `patch.object(...)` доступны для альтернативных вариантов использования.12711272[`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) в качестве декоратора функции, создающего мок и передающего его в декорируемую функцию:12731274```python1275>>> @patch('__main__.SomeClass')1276... def function(normal_argument, mock_class):1277...     print(mock_class is SomeClass)1278...1279>>> function(None)1280True1281```12821283Патч класса заменяет класс на [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) *экземпляр*. Если класс инстанцируется в тестируемом коде, то будет использован [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) мока.12841285Если класс инстанцируется несколько раз, можно использовать [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), чтобы каждый раз возвращать новый мок. В качестве альтернативы можно установить *return\_value* во что угодно.12861287Чтобы настроить возвращаемые значения для методов *экземпляров* патченного класса, это нужно делать на [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value). Например:12881289```python1290>>> class Class:1291...     def method(self):1292...         pass1293...1294>>> with patch('__main__.Class') as MockClass:1295...     instance = MockClass.return_value1296...     instance.method.return_value = 'foo'1297...     assert Class() is instance1298...     assert Class().method() == 'foo'1299...1300```13011302Если используются *spec* или *spec\_set*, и [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) заменяет *класс*, то возвращаемое значение созданного мока будет иметь ту же спецификацию.13031304```python1305>>> Original = Class1306>>> patcher = patch('__main__.Class', spec=True)1307>>> MockClass = patcher.start()1308>>> instance = MockClass()1309>>> assert isinstance(instance, Original)1310>>> patcher.stop()1311```13121313Аргумент *new\_callable* полезен, когда требуется использовать альтернативный класс вместо [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) по умолчанию для создаваемого мока. Например, если нужно использовать [`NonCallableMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.NonCallableMock):13141315```python1316>>> thing = object()1317>>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing:1318...     assert thing is mock_thing1319...     thing()1320...1321Traceback (most recent call last):1322  ...1323TypeError: 'NonCallableMock' object is not callable1324```13251326Ещё один вариант использования – замена объекта на экземпляр [`io.StringIO`](https://python-all.ru/3.15/library/io.html#io.StringIO):13271328```python1329>>> from io import StringIO1330>>> def foo():1331...     print('Something')1332...1333>>> @patch('sys.stdout', new_callable=StringIO)1334... def test(mock_stdout):1335...     foo()1336...     assert mock_stdout.getvalue() == 'Something\n'1337...1338>>> test()1339```13401341Когда [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) создаёт мок, обычно первым делом нужно настроить мок. Часть этой настройки можно выполнить в вызове patch. Любые произвольные именованные аргументы, переданные в вызов, будут использованы для установки атрибутов созданного мока:13421343```python1344>>> patcher = patch('__main__.thing', first='one', second='two')1345>>> mock_thing = patcher.start()1346>>> mock_thing.first1347'one'1348>>> mock_thing.second1349'two'1350```13511352Помимо атрибутов созданного мока, такие атрибуты дочерних моков, как [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) и [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), также можно настроить. Их нельзя передать напрямую как именованные аргументы, но словарь с такими ключами можно развернуть в вызов [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) с помощью `**`:13531354```python1355>>> config = {'method.return_value': 3, 'other.side_effect': KeyError}1356>>> patcher = patch('__main__.thing', **config)1357>>> mock_thing = patcher.start()1358>>> mock_thing.method()135931360>>> mock_thing.other()1361Traceback (most recent call last):1362  ...1363KeyError1364```13651366По умолчанию попытка запатчить несуществующую функцию в модуле (или метод, или атрибут в классе) завершится ошибкой [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError):13671368```python1369>>> @patch('sys.non_existing_attribute', 42)1370... def test():1371...     assert sys.non_existing_attribute == 421372...1373>>> test()1374Traceback (most recent call last):1375  ...1376AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing_attribute'1377```13781379Но добавление `create=True` в вызов [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) заставит предыдущий пример работать как ожидается:13801381```python1382>>> @patch('sys.non_existing_attribute', 42, create=True)1383... def test(mock_stdout):1384...     assert sys.non_existing_attribute == 421385...1386>>> test()1387```13881389Изменено в версии 3.8: [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) теперь возвращает [`AsyncMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock), если цель является асинхронной функцией.13901391### patch.object13921393#### `patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`13941395Заменяет именованный член (*атрибут*) объекта (*цель*) на мок-объект.13961397`patch.object()` можно использовать как декоратор, декоратор класса или менеджер контекста. Аргументы *new*, *spec*, *create*, *spec\_set*, *autospec* и *new\_callable* имеют тот же смысл, что и для [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch). Как и `patch()`, `patch.object()` принимает произвольные именованные аргументы для настройки создаваемого мок-объекта.13981399При использовании в качестве декоратора класса `patch.object()` учитывает `patch.TEST_PREFIX` для выбора методов, которые нужно обернуть.14001401[`patch.object()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.object) можно вызывать с тремя или двумя аргументами. Форма с тремя аргументами принимает объект для патча, имя атрибута и объект, которым нужно заменить атрибут.14021403При вызове с двумя аргументами заменяющий объект опускается, и мок создаётся и передаётся как дополнительный аргумент в декорируемую функцию:14041405```python1406>>> @patch.object(SomeClass, 'class_method')1407... def test(mock_method):1408...     SomeClass.class_method(3)1409...     mock_method.assert_called_with(3)1410...1411>>> test()1412```14131414*spec*, *create* и остальные аргументы [`patch.object()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.object) имеют тот же смысл, что и для [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch).14151416### patch.dict14171418#### `patch.dict(in_dict, values=(), clear=False, **kwargs)`14191420Заменяет словарь или объект, подобный словарю, и восстанавливает исходное состояние словаря после теста, причём восстановленный словарь является копией словаря до теста.14211422*in\_dict* может быть словарём или контейнером, подобным отображению. Если это отображение, оно должно как минимум поддерживать получение, установку и удаление элементов, а также итерацию по ключам.14231424*in\_dict* также может быть строкой, задающей имя словаря, который затем будет получен через импорт.14251426*values* может быть словарём значений для установки в словаре. *values* также может быть итерируемым объектом пар `(key, value)`.14271428Если *clear* равен true, то словарь будет очищен перед установкой новых значений.14291430`patch.dict()` также можно вызывать с произвольными именованными аргументами для установки значений в словаре.14311432Изменено в версии 3.8: `patch.dict()` теперь возвращает пропатченный словарь при использовании в качестве менеджера контекста.14331434[`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) может использоваться как менеджер контекста, декоратор или декоратор класса:14351436```python1437>>> foo = {}1438>>> @patch.dict(foo, {'newkey': 'newvalue'})1439... def test():1440...     assert foo == {'newkey': 'newvalue'}1441...1442>>> test()1443>>> assert foo == {}1444```14451446При использовании в качестве декоратора класса [`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) учитывает `patch.TEST_PREFIX` (по умолчанию `'test'`) для выбора методов, которые нужно обернуть:14471448```python1449>>> import os1450>>> import unittest1451>>> from unittest.mock import patch1452>>> @patch.dict('os.environ', {'newkey': 'newvalue'})1453... class TestSample(unittest.TestCase):1454...     def test_sample(self):1455...         self.assertEqual(os.environ['newkey'], 'newvalue')1456```14571458Если требуется использовать другой префикс для тестов, можно указать его патчерам, задав `patch.TEST_PREFIX`. Подробнее о том, как изменить значение, см. в [TEST\_PREFIX](https://python-all.ru/3.15/library/unittest.mock.html#test-prefix).14591460[`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) позволяет добавлять элементы в словарь или просто даёт тесту изменить словарь, гарантируя, что после завершения теста словарь будет восстановлен.14611462```python1463>>> foo = {}1464>>> with patch.dict(foo, {'newkey': 'newvalue'}) as patched_foo:1465...     assert foo == {'newkey': 'newvalue'}1466...     assert patched_foo == {'newkey': 'newvalue'}1467...     # Вы можете добавлять, обновлять или удалять ключи foo (или patched_foo – это тот же словарь).1468...     patched_foo['spam'] = 'eggs'1469...1470>>> assert foo == {}1471>>> assert patched_foo == {}1472```14731474```python1475>>> import os1476>>> with patch.dict('os.environ', {'newkey': 'newvalue'}):1477...     print(os.environ['newkey'])1478...1479newvalue1480>>> assert 'newkey' not in os.environ1481```14821483Ключевые слова можно использовать в вызове [`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) для установки значений в словаре:14841485```python1486>>> mymodule = MagicMock()1487>>> mymodule.function.return_value = 'fish'1488>>> with patch.dict('sys.modules', mymodule=mymodule):1489...     import mymodule1490...     mymodule.function('some', 'args')1491...1492'fish'1493```14941495[`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) можно применять к объектам, похожим на словарь, но не являющимся таковыми. Как минимум, они должны поддерживать получение, установку и удаление элементов, а также либо итерацию, либо проверку принадлежности. Это соответствует магическим методам [`__getitem__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__getitem__), [`__setitem__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__setitem__), [`__delitem__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__delitem__) и либо [`__iter__()`](https://python-all.ru/3.15/library/stdtypes.html#container.__iter__), либо [`__contains__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__contains__).14961497```python1498>>> class Container:1499...     def __init__(self):1500...         self.values = {}1501...     def __getitem__(self, name):1502...         return self.values[name]1503...     def __setitem__(self, name, value):1504...         self.values[name] = value1505...     def __delitem__(self, name):1506...         del self.values[name]1507...     def __iter__(self):1508...         return iter(self.values)1509...1510>>> thing = Container()1511>>> thing['one'] = 11512>>> with patch.dict(thing, one=2, two=3):1513...     assert thing['one'] == 21514...     assert thing['two'] == 31515...1516>>> assert thing['one'] == 11517>>> assert list(thing) == ['one']1518```15191520### patch.multiple15211522#### `patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)`15231524Выполняет несколько патчей за один вызов. Принимает объект для патча (либо сам объект, либо строку для его импорта) и именованные аргументы для патчей:15251526```python1527with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'):1528    ...1529```15301531Используйте [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT) в качестве значения, если хотите, чтобы `patch.multiple()` создавал моки автоматически. В этом случае созданные моки передаются в декорированную функцию по ключу, а при использовании `patch.multiple()` в качестве менеджера контекста возвращается словарь.15321533`patch.multiple()` можно использовать как декоратор, декоратор класса или менеджер контекста. Аргументы *spec*, *spec\_set*, *create*, *autospec* и *new\_callable* имеют тот же смысл, что и для [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch). Эти аргументы применяются ко *всем* патчам, выполняемым с помощью `patch.multiple()`.15341535При использовании в качестве декоратора класса `patch.multiple()` учитывает `patch.TEST_PREFIX` для выбора методов, которые нужно обернуть.15361537Если требуется, чтобы [`patch.multiple()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.multiple) создавал моки автоматически, можно указать [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT) в качестве значения. При использовании `patch.multiple()` в качестве декоратора созданные моки передаются в декорированную функцию по ключу.15381539```python1540>>> thing = object()1541>>> other = object()15421543>>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)1544... def test_function(thing, other):1545...     assert isinstance(thing, MagicMock)1546...     assert isinstance(other, MagicMock)1547...1548>>> test_function()1549```15501551[`patch.multiple()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.multiple) можно вкладывать в другие декораторы `patch`, но аргументы, передаваемые по ключу, следует указывать *после* любых стандартных аргументов, созданных [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch):15521553```python1554>>> @patch('sys.exit')1555... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)1556... def test_function(mock_exit, other, thing):1557...     assert 'other' in repr(other)1558...     assert 'thing' in repr(thing)1559...     assert 'exit' in repr(mock_exit)1560...1561>>> test_function()1562```15631564Если [`patch.multiple()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.multiple) используется как менеджер контекста, возвращаемое им значение – это словарь, где созданные моки сгруппированы по имени:15651566```python1567>>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values:1568...     assert 'other' in repr(values['other'])1569...     assert 'thing' in repr(values['thing'])1570...     assert values['thing'] is thing1571...     assert values['other'] is other1572...1573```15741575### Методы patch: start и stop15761577У всех патчеров есть методы `start()` и `stop()`. Это упрощает применение патчей в методах `setUp` или в ситуациях, когда требуется выполнить несколько патчей без вложенных декораторов или операторов with.15781579Для их использования вызовите [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch), [`patch.object()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.object) или [`patch.dict()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.dict) как обычно и сохраните ссылку на возвращаемый объект `patcher`. Затем можно вызвать `start()`, чтобы применить патч, и `stop()`, чтобы его отменить.15801581Если [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) используется для создания мока, этот мок будет возвращён вызовом `patcher.start`.15821583```python1584>>> patcher = patch('package.module.ClassName')1585>>> from package import module1586>>> original = module.ClassName1587>>> new_mock = patcher.start()1588>>> assert module.ClassName is not original1589>>> assert module.ClassName is new_mock1590>>> patcher.stop()1591>>> assert module.ClassName is original1592>>> assert module.ClassName is not new_mock1593```15941595Типичный сценарий – выполнение нескольких патчей в методе `setUp` класса [`TestCase`](https://python-all.ru/3.15/library/unittest.html#unittest.TestCase):15961597```python1598>>> class MyTest(unittest.TestCase):1599...     def setUp(self):1600...         self.patcher1 = patch('package.module.Class1')1601...         self.patcher2 = patch('package.module.Class2')1602...         self.MockClass1 = self.patcher1.start()1603...         self.MockClass2 = self.patcher2.start()1604...1605...     def tearDown(self):1606...         self.patcher1.stop()1607...         self.patcher2.stop()1608...1609...     def test_something(self):1610...         assert package.module.Class1 is self.MockClass11611...         assert package.module.Class2 is self.MockClass21612...1613>>> MyTest('test_something').run()1614```16151616> **Внимание**1617>1618> При использовании этой техники необходимо убедиться, что патч «отменён» вызовом `stop`. Это может быть сложнее, чем кажется, потому что если в методе `setUp` возникнет исключение, `tearDown` не будет вызван. [`unittest.TestCase.addCleanup()`](https://python-all.ru/3.15/library/unittest.html#unittest.TestCase.addCleanup) упрощает задачу:1619>1620> ```python1621> >>> class MyTest(unittest.TestCase):1622> ...     def setUp(self):1623> ...         patcher = patch('package.module.Class')1624> ...         self.MockClass = patcher.start()1625> ...         self.addCleanup(patcher.stop)1626> ...1627> ...     def test_something(self):1628> ...         assert package.module.Class is self.MockClass1629> ...1630> ```1631>1632> В качестве дополнительного бонуса больше не нужно хранить ссылку на объект `patcher`.16331634Также можно остановить все запущенные патчи с помощью [`patch.stopall()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.stopall).16351636#### `patch.stopall()`16371638Останавливает все активные патчи. Останавливает только те патчи, которые были запущены с помощью `start`.16391640### Патчинг встроенных функций: patch builtins16411642Можно патчить любые встроенные функции в модуле. В следующем примере патчится встроенная функция [`ord()`](https://python-all.ru/3.15/library/functions.html#ord):16431644```python1645>>> @patch('__main__.ord')1646... def test(mock_ord):1647...     mock_ord.return_value = 1011648...     print(ord('c'))1649...1650>>> test()16511011652```16531654### TEST\_PREFIX16551656Все патчеры можно использовать в качестве декораторов класса. В этом случае они оборачивают каждый тестовый метод класса. Патчеры распознают методы, начинающиеся с `'test'`, как тестовые. Это тот же принцип, по которому [`unittest.TestLoader`](https://python-all.ru/3.15/library/unittest.html#unittest.TestLoader) по умолчанию находит тестовые методы.16571658Возможно, потребуется использовать другой префикс для тестов. Уведомить патчеры о другом префиксе можно, установив `patch.TEST_PREFIX`:16591660```python1661>>> patch.TEST_PREFIX = 'foo'1662>>> value = 31663>>>1664>>> @patch('__main__.value', 'not three')1665... class Thing:1666...     def foo_one(self):1667...         print(value)1668...     def foo_two(self):1669...         print(value)1670...1671>>>1672>>> Thing().foo_one()1673not three1674>>> Thing().foo_two()1675not three1676>>> value167731678```16791680### Вложенные декораторы патча16811682Если нужно выполнить несколько замен, можно просто наложить декораторы друг на друга.16831684Можно накладывать несколько декораторов патча, используя такой шаблон:16851686```python1687>>> @patch.object(SomeClass, 'class_method')1688... @patch.object(SomeClass, 'static_method')1689... def test(mock1, mock2):1690...     assert SomeClass.static_method is mock11691...     assert SomeClass.class_method is mock21692...     SomeClass.static_method('foo')1693...     SomeClass.class_method('bar')1694...     return mock1, mock21695...1696>>> mock1, mock2 = test()1697>>> mock1.assert_called_once_with('foo')1698>>> mock2.assert_called_once_with('bar')1699```17001701Обратите внимание: декораторы применяются снизу вверх. Это стандартный порядок применения декораторов в Python. Порядок созданных заглушек, передаваемых в тестовую функцию, соответствует этому порядку.17021703### Где применять патч17041705[`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) работает, временно заменяя объект, на который указывает *имя*, другим объектом. На один объект может указывать много имён, поэтому для корректной работы патча необходимо заменить имя, используемое тестируемой системой.17061707Основной принцип: патч применяется там, где объект *ищется*, а это не обязательно то же место, где он определён. Несколько примеров помогут прояснить это.17081709Представим проект, который нужно протестировать, со следующей структурой:17101711```python1712a.py1713    -> Defines SomeClass17141715b.py1716    -> from a import SomeClass1717    -> some_function instantiates SomeClass1718```17191720Теперь нужно протестировать `some_function`, но мы хотим подменить `SomeClass` с помощью [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch). Проблема в том, что при импорте модуля b, который будет импортировать `SomeClass` из модуля a, если использовать `patch()` для подмены `a.SomeClass`, это не повлияет на тест: модуль b уже содержит ссылку на *настоящий* `SomeClass`, и патч не сработает.17211722Ключ в том, чтобы заменить `SomeClass` там, где он используется (или где происходит поиск). В этом случае `some_function` будет искать `SomeClass` в модуле b, куда он был импортирован. Замена должна выглядеть так:17231724```python1725@patch('b.SomeClass')1726```17271728Однако рассмотрим альтернативный сценарий: вместо `from a import SomeClass` модуль b выполняет `import a`, и `some_function` использует `a.SomeClass`. Обе формы импорта распространены. В этом случае класс, который нужно заменить, ищется в модуле, поэтому заменять нужно `a.SomeClass`:17291730```python1731@patch('a.SomeClass')1732```17331734### Замена дескрипторов и прокси-объектов17351736И [patch](https://python-all.ru/3.15/library/unittest.mock.html#patch), и [patch.object](https://python-all.ru/3.15/library/unittest.mock.html#patch-object) корректно заменяют и восстанавливают дескрипторы: методы класса, статические методы и свойства. Заменять их следует на *классе*, а не на экземпляре. Они также работают с *некоторыми* объектами, проксирующими доступ к атрибутам, например, [объект настроек Django](https://python-all.ru/3.15/library/unittest.mock.html).17371738## MagicMock и поддержка магических методов17391740### Подмена магических методов17411742[`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) поддерживает подмену методов протоколов Python, также известных как [«магические методы»](https://python-all.ru/3.15/glossary.html#term-magic-method). Это позволяет объектам-заглушкам заменять контейнеры и другие объекты, реализующие протоколы Python.17431744Поскольку магические методы ищутся иначе, чем обычные методы [\[2\]](https://python-all.ru/3.15/library/unittest.mock.html#id9), эта поддержка была реализована специально. Это означает, что поддерживаются только определённые магические методы. Список поддерживаемых методов включает *почти* все. Если каких-то не хватает, пожалуйста, сообщите.17451746Магические методы подменяются установкой нужного метода в функцию или экземпляр заглушки. Если используется функция, она *должна* принимать `self` в качестве первого аргумента [\[3\]](https://python-all.ru/3.15/library/unittest.mock.html#id10).17471748```python1749>>> def __str__(self):1750...     return 'fooble'1751...1752>>> mock = Mock()1753>>> mock.__str__ = __str__1754>>> str(mock)1755'fooble'1756```17571758```python1759>>> mock = Mock()1760>>> mock.__str__ = Mock()1761>>> mock.__str__.return_value = 'fooble'1762>>> str(mock)1763'fooble'1764```17651766```python1767>>> mock = Mock()1768>>> mock.__iter__ = Mock(return_value=iter([]))1769>>> list(mock)1770[]1771```17721773Один из вариантов использования – подмена объектов, используемых как контекстные менеджеры в операторе [`with`](https://python-all.ru/3.15/reference/compound_stmts.html#with):17741775```python1776>>> mock = Mock()1777>>> mock.__enter__ = Mock(return_value='foo')1778>>> mock.__exit__ = Mock(return_value=False)1779>>> with mock as m:1780...     assert m == 'foo'1781...1782>>> mock.__enter__.assert_called_with()1783>>> mock.__exit__.assert_called_with(None, None, None)1784```17851786Вызовы магических методов не отображаются в [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls), но записываются в [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls).17871788> **Примечание**1789>1790> Если при создании заглушки использовать именованный аргумент *spec*, то попытка установить магический метод, отсутствующий в спецификации, вызовет [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).17911792Полный список поддерживаемых магических методов:17931794- `__hash__`, `__sizeof__`, `__repr__` и `__str__`1795- `__dir__`, `__format__` и `__subclasses__`1796- `__round__`, `__floor__`, `__trunc__` и `__ceil__`1797- Сравнения: `__lt__`, `__gt__`, `__le__`, `__ge__`, `__eq__` и `__ne__`1798- Методы контейнеров: `__getitem__`, `__setitem__`, `__delitem__`, `__contains__`, `__len__`, `__iter__`, `__reversed__` и `__missing__`1799- Контекстный менеджер: `__enter__`, `__exit__`, `__aenter__` и `__aexit__`1800- Унарные числовые методы: `__neg__`, `__pos__` и `__invert__`1801- Числовые методы (включая правосторонние и варианты с подстановкой на месте): `__add__`, `__sub__`, `__mul__`, `__matmul__`, `__truediv__`, `__floordiv__`, `__mod__`, `__divmod__`, `__lshift__`, `__rshift__`, `__and__`, `__xor__`, `__or__` и `__pow__`1802- Методы числового преобразования: `__complex__`, `__int__`, `__float__` и `__index__`1803- Методы дескрипторов: `__get__`, `__set__` и `__delete__`1804- Сериализация (pickling): `__reduce__`, `__reduce_ex__`, `__getinitargs__`, `__getnewargs__`, `__getstate__` и `__setstate__`1805- Представление пути файловой системы: `__fspath__`1806- Методы асинхронной итерации: `__aiter__` и `__anext__`18071808Изменено в версии 3.8: Добавлена поддержка [`os.PathLike.__fspath__()`](https://python-all.ru/3.15/library/os.html#os.PathLike.__fspath__).18091810Изменено в версии 3.8: Добавлена поддержка `__aenter__`, `__aexit__`, `__aiter__` и `__anext__`.18111812Следующие методы существуют, но *не* поддерживаются, так как либо используются в mock, либо не могут быть установлены динамически, либо могут вызывать проблемы:18131814- `__getattr__`, `__setattr__`, `__init__` и `__new__`1815- `__prepare__`, `__instancecheck__`, `__subclasscheck__`, `__del__`18161817### Магический макет18181819Существует два `MagicMock` варианта: [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) и [`NonCallableMagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.NonCallableMagicMock).18201821#### `class unittest.mock.MagicMock(*args, **kw)`18221823`MagicMock` является подклассом [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) с реализациями по умолчанию большинства [магических методов](https://python-all.ru/3.15/glossary.html#term-magic-method). Можно использовать `MagicMock`, не настраивая магические методы самостоятельно.18241825Параметры конструктора имеют тот же смысл, что и для [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock).18261827Если используются аргументы *spec* или *spec\_set*, то будут созданы *только* магические методы, которые существуют в спецификации.18281829#### `class unittest.mock.NonCallableMagicMock(*args, **kw)`18301831Невызываемая версия [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock).18321833Параметры конструктора имеют тот же смысл, что и для [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock), за исключением *return\_value* и *side\_effect*, которые не имеют смысла для невызываемого mock.18341835Магические методы настраиваются с помощью объектов [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock), поэтому их можно настраивать и использовать обычным образом:18361837```python1838>>> mock = MagicMock()1839>>> mock[3] = 'fish'1840>>> mock.__setitem__.assert_called_with(3, 'fish')1841>>> mock.__getitem__.return_value = 'result'1842>>> mock[2]1843'result'1844```18451846По умолчанию многие методы протокола должны возвращать объекты определенного типа. Эти методы предварительно настроены с возвращаемым значением по умолчанию, так что их можно использовать, ничего не делая, если возвращаемое значение не интересует. Вы всё еще можете *установить* возвращаемое значение вручную, если хотите изменить значение по умолчанию.18471848Методы и их значения по умолчанию:18491850- `__lt__`: [`NotImplemented`](https://python-all.ru/3.15/library/constants.html#NotImplemented)1851- `__gt__`: `NotImplemented`1852- `__le__`: `NotImplemented`1853- `__ge__`: `NotImplemented`1854- `__int__`: `1`1855- `__contains__`: `False`1856- `__len__`: `0`1857- `__iter__`: `iter([])`1858- `__exit__`: `False`1859- `__aexit__`: `False`1860- `__complex__`: `1j`1861- `__float__`: `1.0`1862- `__bool__`: `True`1863- `__index__`: `1`1864- `__hash__`: хэш по умолчанию для mock1865- `__str__`: строковое представление по умолчанию для mock1866- `__sizeof__`: размер по умолчанию для mock18671868Например:18691870```python1871>>> mock = MagicMock()1872>>> int(mock)187311874>>> len(mock)187501876>>> list(mock)1877[]1878>>> object() in mock1879False1880```18811882Два метода сравнения, `__eq__()` и `__ne__()`, являются особенными. Они выполняют сравнение на равенство по умолчанию по идентичности, используя атрибут [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), если не изменить их возвращаемое значение на что-то другое:18831884```python1885>>> MagicMock() == 31886False1887>>> MagicMock() != 31888True1889>>> mock = MagicMock()1890>>> mock.__eq__.return_value = True1891>>> mock == 31892True1893```18941895Возвращаемое значение `__iter__()` может быть любым итерируемым объектом и не обязательно должно быть итератором:18961897```python1898>>> mock = MagicMock()1899>>> mock.__iter__.return_value = ['a', 'b', 'c']1900>>> list(mock)1901['a', 'b', 'c']1902>>> list(mock)1903['a', 'b', 'c']1904```19051906Если возвращаемое значение *является* итератором, то однократная итерация по нему израсходует его, и последующие итерации приведут к пустому списку:19071908```python1909>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])1910>>> list(mock)1911['a', 'b', 'c']1912>>> list(mock)1913[]1914```19151916`MagicMock` имеет все поддерживаемые магические методы, настроенные, за исключением некоторых малоизвестных и устаревших. Вы всё еще можете настроить их, если захотите.19171918Магические методы, которые поддерживаются, но не настроены по умолчанию в `MagicMock`:19191920- `__subclasses__`1921- `__dir__`1922- `__format__`1923- `__get__`, `__set__` и `__delete__`1924- `__reversed__` и `__missing__`1925- `__reduce__`, `__reduce_ex__`, `__getinitargs__`, `__getnewargs__`, `__getstate__` и `__setstate__`1926- `__getformat__`19271928\[[2](https://python-all.ru/3.15/library/unittest.mock.html#id7)\]19291930Магические методы *должны* искаться в классе, а не в экземпляре. Разные версии Python непоследовательны в применении этого правила. Поддерживаемые методы протокола должны работать во всех поддерживаемых версиях Python.19311932\[[3](https://python-all.ru/3.15/library/unittest.mock.html#id8)\]19331934Функция в основном привязана к классу, но каждый экземпляр `Mock` изолирован от остальных.19351936## Вспомогательные функции19371938### sentinel19391940#### `unittest.mock.sentinel`19411942Объект `sentinel` предоставляет удобный способ создания уникальных объектов для тестов.19431944Атрибуты создаются по запросу при обращении к ним по имени. Обращение к одному и тому же атрибуту всегда возвращает один и тот же объект. Возвращаемые объекты имеют понятное строковое представление (repr), чтобы сообщения об ошибках тестов были читаемыми.19451946Изменено в версии 3.7: Атрибуты `sentinel` теперь сохраняют свою идентичность при их [`copied`](https://python-all.ru/3.15/library/copy.html#module-copy) или [`pickled`](https://python-all.ru/3.15/library/pickle.html#module-pickle).19471948Иногда при тестировании нужно проверить, что определённый объект передаётся как аргумент другому методу или возвращается. Часто для этого создают именованные sentinel-объекты. [`sentinel`](https://python-all.ru/3.15/library/functions.html#sentinel) предоставляет удобный способ создания и проверки идентичности таких объектов.19491950В этом примере мы применяем монки-патчинг к `method`, чтобы он возвращал `sentinel.some_object`:19511952```python1953>>> real = ProductionClass()1954>>> real.method = Mock(name="method")1955>>> real.method.return_value = sentinel.some_object1956>>> result = real.method()1957>>> assert result is sentinel.some_object1958>>> result1959sentinel.some_object1960```19611962### DEFAULT19631964#### `unittest.mock.DEFAULT`19651966Объект `DEFAULT` – это предварительно созданный sentinel (фактически `sentinel.DEFAULT`). Он может использоваться функциями [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), чтобы указать, что следует использовать обычное возвращаемое значение.19671968### call19691970#### `unittest.mock.call(*args, **kwargs)`19711972`call()` – это вспомогательный объект для упрощения утверждений, для сравнения с [`call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args), [`call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list), [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) и [`method_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.method_calls). `call()` также можно использовать с [`assert_has_calls()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls).19731974```python1975>>> m = MagicMock(return_value=None)1976>>> m(1, 2, a='foo', b='bar')1977>>> m()1978>>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()]1979True1980```19811982#### `call.call_list()`19831984Для объекта call, представляющего несколько вызовов, `call_list()` возвращает список всех промежуточных вызовов, а также финального вызова.19851986`call_list` особенно полезен для проверки «цепочных вызовов». Цепочный вызов – это несколько вызовов в одной строке кода. В результате в [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls) макета появляется несколько записей. Ручное построение последовательности вызовов может быть утомительным.19871988[`call_list()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.call.call_list) может построить последовательность вызовов из того же цепочного вызова:19891990```python1991>>> m = MagicMock()1992>>> m(1).method(arg='foo').other('bar')(2.0)1993<MagicMock name='mock().method().other()()' id='...'>1994>>> kall = call(1).method(arg='foo').other('bar')(2.0)1995>>> kall.call_list()1996[call(1),1997 call().method(arg='foo'),1998 call().method().other('bar'),1999 call().method().other()(2.0)]2000>>> m.mock_calls == kall.call_list()2001True2002```20032004Объект `call` представляет собой либо кортеж (позиционные аргументы, именованные аргументы), либо (имя, позиционные аргументы, именованные аргументы) в зависимости от того, как он был создан. При самостоятельном создании это не особо важно, но объекты `call`, находящиеся в атрибутах [`Mock.call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args), [`Mock.call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list) и [`Mock.mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls), можно интроспектировать, чтобы получить отдельные аргументы, которые они содержат.20052006Объекты `call` в [`Mock.call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args) и [`Mock.call_args_list`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args_list) представляют собой кортежи из двух элементов (позиционные аргументы, именованные аргументы), тогда как объекты `call` в [`Mock.mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls), а также создаваемые вручную, являются кортежами из трёх элементов (имя, позиционные аргументы, именованные аргументы).20072008Вы можете использовать их «кортежность», чтобы извлекать отдельные аргументы для более сложной интроспекции и проверок. Позиционные аргументы – это кортеж (пустой кортеж, если позиционных аргументов нет), а именованные аргументы – это словарь:20092010```python2011>>> m = MagicMock(return_value=None)2012>>> m(1, 2, 3, arg='one', arg2='two')2013>>> kall = m.call_args2014>>> kall.args2015(1, 2, 3)2016>>> kall.kwargs2017{'arg': 'one', 'arg2': 'two'}2018>>> kall.args is kall[0]2019True2020>>> kall.kwargs is kall[1]2021True2022```20232024```python2025>>> m = MagicMock()2026>>> m.foo(4, 5, 6, arg='two', arg2='three')2027<MagicMock name='mock.foo()' id='...'>2028>>> kall = m.mock_calls[0]2029>>> name, args, kwargs = kall2030>>> name2031'foo'2032>>> args2033(4, 5, 6)2034>>> kwargs2035{'arg': 'two', 'arg2': 'three'}2036>>> name is m.mock_calls[0][0]2037True2038```20392040### create\_autospec20412042#### `unittest.mock.create_autospec(spec, spec_set=False, instance=False, **kwargs)`20432044Создаёт макет-объект, используя другой объект в качестве спецификации. Атрибуты макета будут использовать соответствующий атрибут объекта *spec* в качестве своей спецификации.20452046У макетируемых функций или методов будут проверяться аргументы, чтобы убедиться, что они вызываются с правильной сигнатурой.20472048Если *spec\_set* равен `True`, то попытка установить атрибуты, которых нет в объекте спецификации, вызовет исключение [`AttributeError`](https://python-all.ru/3.15/library/exceptions.html#AttributeError).20492050Если в качестве спецификации используется класс, то возвращаемое значение макета (экземпляр класса) будет иметь ту же спецификацию. Вы можете использовать класс в качестве спецификации для объекта-экземпляра, передав `instance=True`. Возвращаемый макет будет вызываемым, только если экземпляры макета вызываемы.20512052`create_autospec()` также принимает произвольные именованные аргументы, которые передаются конструктору создаваемого макета.20532054Смотрите [Autospeccing](https://python-all.ru/3.15/library/unittest.mock.html#auto-speccing) для примеров использования автоспецификации с [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec) и аргументом *autospec* для [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch).20552056Изменено в версии 3.8: [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec) теперь возвращает [`AsyncMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.AsyncMock), если цель является асинхронной функцией.20572058### ANY20592060#### `unittest.mock.ANY`20612062Иногда может потребоваться сделать утверждения о *некоторых* аргументах вызова макета, но либо некоторые аргументы не важны, либо нужно извлечь их по отдельности из [`call_args`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.call_args) и сделать более сложные проверки.20632064Чтобы игнорировать определённые аргументы, можно передавать объекты, которые сравниваются равными с *чем угодно*. Вызовы [`assert_called_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_with) и [`assert_called_once_with()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.assert_called_once_with) тогда будут успешными независимо от того, что было передано.20652066```python2067>>> mock = Mock(return_value=None)2068>>> mock('foo', bar=object())2069>>> mock.assert_called_once_with('foo', bar=ANY)2070```20712072[`ANY`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.ANY) также можно использовать в сравнениях со списками вызовов, например: [`mock_calls`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.mock_calls):20732074```python2075>>> m = MagicMock(return_value=None)2076>>> m(1)2077>>> m(1, 2)2078>>> m(object())2079>>> m.mock_calls == [call(1), call(1, 2), ANY]2080True2081```20822083[`ANY`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.ANY) не ограничивается сравнениями с объектами вызовов, поэтому его также можно использовать в утверждениях тестов:20842085```python2086class TestStringMethods(unittest.TestCase):20872088    def test_split(self):2089        s = 'hello world'2090        self.assertEqual(s.split(), ['hello', ANY])2091```20922093### FILTER\_DIR20942095#### `unittest.mock.FILTER_DIR`20962097[`FILTER_DIR`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.FILTER_DIR) – это переменная уровня модуля, которая управляет тем, как mock-объекты реагируют на [`dir()`](https://python-all.ru/3.15/library/functions.html#dir). По умолчанию используется `True`, который применяет описанную ниже фильтрацию, чтобы показывать только полезные атрибуты. Если вам не нравится эта фильтрация или нужно отключить её для диагностики, установите `mock.FILTER_DIR = False`.20982099При включённой фильтрации `dir(some_mock)` показывает только полезные атрибуты и будет включать любые динамически созданные атрибуты, которые обычно не отображаются. Если mock был создан с *spec* (или, конечно, *autospec*), то показываются все атрибуты оригинала, даже если к ним ещё не обращались:21002101```pycon2102>>> dir(Mock())2103['assert_any_call',2104 'assert_called',2105 'assert_called_once',2106 'assert_called_once_with',2107 'assert_called_with',2108 'assert_has_calls',2109 'assert_not_called',2110 'attach_mock',2111 ...2112>>> from urllib import request2113>>> dir(Mock(spec=request))2114['AbstractBasicAuthHandler',2115 'AbstractDigestAuthHandler',2116 'AbstractHTTPHandler',2117 'BaseHandler',2118 ...2119```21202121Многие не очень полезные атрибуты (приватные для [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock), а не для того, что имитируется) с префиксом из одного или двух подчёркиваний были отфильтрованы из результата вызова [`dir()`](https://python-all.ru/3.15/library/functions.html#dir) на `Mock`. Если вам не нравится такое поведение, вы можете отключить его, установив переключатель уровня модуля [`FILTER_DIR`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.FILTER_DIR):21222123```pycon2124>>> from unittest import mock2125>>> mock.FILTER_DIR = False2126>>> dir(mock.Mock())2127['_NonCallableMock__get_return_value',2128 '_NonCallableMock__get_side_effect',2129 '_NonCallableMock__return_value_doc',2130 '_NonCallableMock__set_return_value',2131 '_NonCallableMock__set_side_effect',2132 '__call__',2133 '__class__',2134 ...2135```21362137В качестве альтернативы вы можете просто использовать `vars(my_mock)` (атрибуты экземпляра) и `dir(type(my_mock))` (атрибуты типа), чтобы обойти фильтрацию независимо от [`FILTER_DIR`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.FILTER_DIR).21382139### mock\_open21402141#### `unittest.mock.mock_open(mock=None, read_data='')`21422143Вспомогательная функция для создания mock для замены использования [`open()`](https://python-all.ru/3.15/library/functions.html#open). Она работает для `open()`, вызываемого напрямую или используемого как контекстный менеджер.21442145Аргумент *mock* – это настраиваемый объект mock. Если `None` (по умолчанию), то для вас будет создан [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) с API, ограниченным методами или атрибутами, доступными у стандартных файловых дескрипторов.21462147*read\_data* – это строка, которую методы [`read()`](https://python-all.ru/3.15/library/io.html#io.RawIOBase.read), [`readline()`](https://python-all.ru/3.15/library/io.html#io.IOBase.readline) и [`readlines()`](https://python-all.ru/3.15/library/io.html#io.IOBase.readlines) файлового хендла должны возвращать. Вызовы этих методов будут брать данные из *read\_data*, пока она не исчерпается. Mock этих методов довольно примитивен: каждый раз при вызове *mock* *read\_data* перематывается к началу. Если вам нужен больший контроль над данными, которые вы передаёте тестируемому коду, вам придётся настроить этот mock самостоятельно. Если этого недостаточно, один из пакетов для файловой системы в памяти на [PyPI](https://python-all.ru/3.15/library/unittest.mock.html) может предложить реалистичную файловую систему для тестирования.21482149Изменено в версии 3.4: Добавлена поддержка [`readline()`](https://python-all.ru/3.15/library/io.html#io.IOBase.readline) и [`readlines()`](https://python-all.ru/3.15/library/io.html#io.IOBase.readlines). Mock для [`read()`](https://python-all.ru/3.15/library/io.html#io.RawIOBase.read) изменён – теперь он потребляет *read\_data*, а не возвращает её при каждом вызове.21502151Изменено в версии 3.5: Теперь *read\_data* сбрасывается при каждом вызове *mock*.21522153Изменено в версии 3.8: Добавлен [`__iter__()`](https://python-all.ru/3.15/library/stdtypes.html#container.__iter__) в реализацию, чтобы итерация (например, в циклах for) корректно потребляла *read\_data*.21542155Использование [`open()`](https://python-all.ru/3.15/library/functions.html#open) как контекстного менеджера – отличный способ гарантировать, что ваши файловые хендлы будут правильно закрыты, и это становится всё более распространённым:21562157```python2158with open('/some/path', 'w') as f:2159    f.write('something')2160```21612162Проблема в том, что даже если вы замокаете вызов [`open()`](https://python-all.ru/3.15/library/functions.html#open), именно *возвращаемый объект* используется как контекстный менеджер (и у него вызываются [`__enter__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__enter__) и [`__exit__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__exit__)).21632164Мокать контекстные менеджеры с помощью [`MagicMock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.MagicMock) достаточно распространено и замороченно, поэтому вспомогательная функция полезна.21652166```python2167>>> m = mock_open()2168>>> with patch('__main__.open', m):2169...     with open('foo', 'w') as h:2170...         h.write('some stuff')2171...2172>>> m.mock_calls2173[call('foo', 'w'),2174 call().__enter__(),2175 call().write('some stuff'),2176 call().__exit__(None, None, None)]2177>>> m.assert_called_once_with('foo', 'w')2178>>> handle = m()2179>>> handle.write.assert_called_once_with('some stuff')2180```21812182А для чтения файлов:21832184```python2185>>> with patch('__main__.open', mock_open(read_data='bibble')) as m:2186...     with open('foo') as h:2187...         result = h.read()2188...2189>>> m.assert_called_once_with('foo')2190>>> assert result == 'bibble'2191```21922193### Автоспецификация21942195Autospeccing основан на существующей `spec` функции mock. Он ограничивает API mock-объектов API исходного объекта (spec), но является рекурсивным (реализован лениво), поэтому атрибуты mock имеют только те же API, что и атрибуты spec. Кроме того, замоканные функции/методы имеют ту же сигнатуру вызова, что и оригинал, поэтому они вызывают [`TypeError`](https://python-all.ru/3.15/library/exceptions.html#TypeError), если вызваны неправильно.21962197Прежде чем я объясню, как работает автоспекинг, вот почему он нужен.21982199[`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) – это очень мощный и гибкий объект, но у него есть недостаток, свойственный мокам в целом. Если вы рефакторите свой код, переименовываете члены и т.д., любые тесты для кода, который всё ещё использует *старое API*, но использует моки вместо реальных объектов, всё равно будут проходить. Это означает, что все тесты могут проходить, даже если ваш код сломан.22002201Изменено в версии 3.5: До версии 3.5 тесты с опечаткой в слове assert молча проходили, хотя должны были вызывать ошибку. Вы всё ещё можете добиться такого поведения, передав `unsafe=True` в Mock.22022203Обратите внимание, что это ещё одна причина, по которой нужны интеграционные тесты, а не только модульные. Тестировать всё изолированно – это хорошо, но если вы не тестируете, как ваши модули «соединены вместе», всё ещё остаётся много места для ошибок, которые тесты могли бы выявить.22042205`unittest.mock` уже предоставляет функцию для этого, называемую speccing. Если вы используете класс или экземпляр в качестве `spec` для mock, то вы можете получить доступ только к тем атрибутам mock, которые существуют в реальном классе:22062207```python2208>>> from urllib import request2209>>> mock = Mock(spec=request.Request)2210>>> mock.assret_called_with  # Преднамеренная опечатка!2211Traceback (most recent call last):2212 ...2213AttributeError: Mock object has no attribute 'assret_called_with'2214```22152216Spec применяется только к самому mock, поэтому у нас всё ещё есть та же проблема с любыми методами на mock:22172218```pycon2219>>> mock.header_items()2220<mock.Mock object at 0x...>2221>>> mock.header_items.assret_called_with()  # Преднамеренная опечатка!2222```22232224Auto-speccing решает эту проблему. Вы можете передать `autospec=True` в [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) / [`patch.object()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch.object) или использовать функцию [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec), чтобы создать mock с spec. Если вы используете аргумент `autospec=True` для `patch()`, то заменяемый объект будет использоваться как объект spec. Поскольку speccing выполняется «лениво» (spec создаётся по мере доступа к атрибутам mock), вы можете использовать его с очень сложными или глубоко вложенными объектами (например, модулями, которые импортируют модули, которые импортируют модули) без большого удара по производительности.22252226Вот пример его использования:22272228```python2229>>> from urllib import request2230>>> patcher = patch('__main__.request', autospec=True)2231>>> mock_request = patcher.start()2232>>> request is mock_request2233True2234>>> mock_request.Request2235<MagicMock name='request.Request' spec='Request' id='...'>2236```22372238Вы можете видеть, что у `request.Request` есть spec. `request.Request` принимает два аргумента в конструкторе (один из них – *self*). Вот что произойдёт, если мы попробуем вызвать его неправильно:22392240```python2241>>> req = request.Request()2242Traceback (most recent call last):2243 ...2244TypeError: <lambda>() takes at least 2 arguments (1 given)2245```22462247Spec также применяется к инстанцированным классам (т.е. возвращаемому значению specced-моков):22482249```python2250>>> req = request.Request('foo')2251>>> req2252<NonCallableMagicMock name='request.Request()' spec='Request' id='...'>2253```22542255Объекты `Request` не являются вызываемыми, поэтому возвращаемое значение при создании экземпляра нашей имитации `request.Request` – это невызываемая заглушка. При наличии спецификации любые опечатки в утверждениях вызовут правильное исключение:22562257```python2258>>> req.add_header('spam', 'eggs')2259<MagicMock name='request.Request().add_header()' id='...'>2260>>> req.add_header.assret_called_with  # Преднамеренная опечатка!2261Traceback (most recent call last):2262 ...2263AttributeError: Mock object has no attribute 'assret_called_with'2264>>> req.add_header.assert_called_with('spam', 'eggs')2265```22662267Во многих случаях достаточно добавить `autospec=True` к существующим вызовам [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch), и это защитит от ошибок из-за опечаток и изменений API.22682269Помимо использования *autospec* через [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch), существует [`create_autospec()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.create_autospec) для создания autospec-моков напрямую:22702271```python2272>>> from urllib import request2273>>> mock_request = create_autospec(request)2274>>> mock_request.Request('foo', 'bar')2275<NonCallableMagicMock name='mock.Request()' spec='Request' id='...'>2276```22772278Однако у этого подхода есть оговорки и ограничения, поэтому он не используется по умолчанию. Чтобы узнать, какие атрибуты доступны у объекта спецификации, autospec должен интроспектировать (получать доступ к атрибутам) спецификацию. Когда вы обращаетесь к атрибутам мока, под капотом происходит аналогичный обход оригинального объекта. Если у каких-то из ваших специфицированных объектов есть свойства или дескрипторы, которые могут запускать выполнение кода, то использовать autospec может не получиться. С другой стороны, гораздо лучше проектировать объекты так, чтобы интроспекция была безопасной [\[4\]](https://python-all.ru/3.15/library/unittest.mock.html#id12).22792280Более серьёзная проблема заключается в том, что атрибуты экземпляра часто создаются в методе [`__init__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__init__) и вообще не существуют на уровне класса. *autospec* не может знать о динамически созданных атрибутах и ограничивает API только видимыми атрибутами.22812282```python2283>>> class Something:2284...   def __init__(self):2285...     self.a = 332286...2287>>> with patch('__main__.Something', autospec=True):2288...   thing = Something()2289...   thing.a2290...2291Traceback (most recent call last):2292  ...2293AttributeError: Mock object has no attribute 'a'2294```22952296Существует несколько способов решить эту проблему. Самый простой (хотя и не обязательно наименее раздражающий) – просто установить нужные атрибуты на моке после его создания. То, что *autospec* не позволяет получать атрибуты, которых нет в спецификации, не мешает вам их устанавливать:22972298```python2299>>> with patch('__main__.Something', autospec=True):2300...   thing = Something()2301...   thing.a = 332302...2303```23042305Существует более строгая версия как *spec*, так и *autospec*, которая *не позволяет* устанавливать несуществующие атрибуты. Это полезно, если вы хотите гарантировать, что ваш код *устанавливает* только допустимые атрибуты, но, очевидно, это блокирует данный конкретный сценарий:23062307```python2308>>> with patch('__main__.Something', autospec=True, spec_set=True):2309...   thing = Something()2310...   thing.a = 332311...2312Traceback (most recent call last):2313 ...2314AttributeError: Mock object has no attribute 'a'2315```23162317Вероятно, лучший способ решения проблемы – добавить атрибуты класса в качестве значений по умолчанию для членов экземпляра, инициализируемых в [`__init__()`](https://python-all.ru/3.15/reference/datamodel.html#object.__init__). Обратите внимание: если вы устанавливаете только атрибуты по умолчанию в `__init__()`, то предоставление их через атрибуты класса (общие для экземпляров, разумеется) тоже будет быстрее. Например:23182319```python2320class Something:2321    a = 332322```23232324Это поднимает ещё одну проблему. Довольно часто в качестве значения по умолчанию для членов, которые позже станут объектами другого типа, используется `None`. `None` была бы бесполезна в качестве спецификации, потому что не позволила бы обращаться *ни к каким* атрибутам или методам. Поскольку `None` *никогда* не будет полезна как спецификация и, вероятно, указывает на член, который обычно имеет другой тип, автоспецификация не использует спецификацию для членов, установленных в `None`. Они будут просто обычными заглушками (точнее, магическими заглушками):23252326```python2327>>> class Something:2328...     member = None2329...2330>>> mock = create_autospec(Something)2331>>> mock.member.foo.bar.baz()2332<MagicMock name='mock.member.foo.bar.baz()' id='...'>2333```23342335Если изменение ваших производственных классов для добавления значений по умолчанию вам не по душе, есть и другие варианты. Один из них – просто использовать экземпляр в качестве спецификации вместо класса. Другой – создать подкласс производственного класса и добавить значения по умолчанию в подкласс, не затрагивая производственный класс. Оба варианта требуют использования альтернативного объекта в качестве спецификации. К счастью, [`patch()`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.patch) поддерживает это – можно просто передать альтернативный объект в качестве аргумента *autospec*:23362337```python2338>>> class Something:2339...   def __init__(self):2340...     self.a = 332341...2342>>> class SomethingForTest(Something):2343...   a = 332344...2345>>> p = patch('__main__.Something', autospec=SomethingForTest)2346>>> mock = p.start()2347>>> mock.a2348<NonCallableMagicMock name='Something.a' spec='int' id='...'>2349```23502351\[[4](https://python-all.ru/3.15/library/unittest.mock.html#id11)\]23522353Это относится только к классам или уже созданным объектам. Вызов имитированного класса для создания экземпляра мока *не создаёт* реальный экземпляр. Выполняются только обращения к атрибутам – наряду с вызовами [`dir()`](https://python-all.ru/3.15/library/functions.html#dir).23542355### Запечатывание моков23562357#### `unittest.mock.seal(mock)`23582359Функция seal отключает автоматическое создание моков при обращении к атрибуту запечатываемого мока или рекурсивно к любым его атрибутам, которые уже являются моками.23602361Если экземпляру мока с именем или спецификацией присваивается атрибут, он не будет учитываться в цепочке запечатывания. Это позволяет предотвратить запечатывание части мок-объекта.23622363```python2364>>> mock = Mock()2365>>> mock.submock.attribute1 = 22366>>> mock.not_submock = mock.Mock(name="sample_name")2367>>> seal(mock)2368>>> mock.new_attribute  # Это вызовет AttributeError.2369>>> mock.submock.attribute2  # Это вызовет AttributeError.2370>>> mock.not_submock.attribute2  # Это не вызовет исключения.2371```23722373Добавлено в версии 3.7.23742375## Порядок приоритета `side_effect`, `return_value` и *wraps*23762377Порядок их приоритета:237823791. [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect)23802. [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value)23813. *wraps*23822383Если установлены все три, mock вернёт значение из [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), полностью игнорируя [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) и обёрнутый объект. Если установлены любые два, тот, у которого более высокий приоритет, вернёт значение. Независимо от того, какой был установлен первым, порядок приоритета остаётся неизменным.23842385```python2386>>> from unittest.mock import Mock2387>>> class Order:2388...     @staticmethod2389...     def get_value():2390...         return "third"2391...2392>>> order_mock = Mock(spec=Order, wraps=Order)2393>>> order_mock.get_value.side_effect = ["first"]2394>>> order_mock.get_value.return_value = "second"2395>>> order_mock.get_value()2396'first'2397```23982399Поскольку `None` – это значение по умолчанию для [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), если вы переназначите его значение обратно на `None`, порядок приоритета будет проверяться между [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) и обёрнутым объектом, игнорируя `side_effect`.24002401```python2402>>> order_mock.get_value.side_effect = None2403>>> order_mock.get_value()2404'second'2405```24062407Если значение, возвращаемое [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect), равно [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT), оно игнорируется, и порядок приоритета переходит к следующему элементу для получения возвращаемого значения.24082409```python2410>>> from unittest.mock import DEFAULT2411>>> order_mock.get_value.side_effect = [DEFAULT]2412>>> order_mock.get_value()2413'second'2414```24152416Когда [`Mock`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock) оборачивает объект, значением по умолчанию для [`return_value`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.return_value) будет [`DEFAULT`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.DEFAULT).24172418```python2419>>> order_mock = Mock(spec=Order, wraps=Order)2420>>> order_mock.return_value2421sentinel.DEFAULT2422>>> order_mock.get_value.return_value2423sentinel.DEFAULT2424```24252426Порядок приоритета проигнорирует это значение и перейдёт к последнему элементу, которым является обёрнутый объект.24272428Поскольку реальный вызов направляется на обёрнутый объект, создание экземпляра этого мока вернёт реальный экземпляр класса. Позиционные аргументы, если они требуются обёрнутому объекту, должны быть переданы.24292430```python2431>>> order_mock_instance = order_mock()2432>>> isinstance(order_mock_instance, Order)2433True2434>>> order_mock_instance.get_value()2435'third'2436```24372438```python2439>>> order_mock.get_value.return_value = DEFAULT2440>>> order_mock.get_value()2441'third'2442```24432444```python2445>>> order_mock.get_value.return_value = "second"2446>>> order_mock.get_value()2447'second'2448```24492450Но если вы присвоите ему `None`, оно не будет проигнорировано, поскольку это явное присваивание. Таким образом, порядок приоритета не перейдёт к обёрнутому объекту.24512452```python2453>>> order_mock.get_value.return_value = None2454>>> order_mock.get_value() is None2455True2456```24572458Даже если вы установите все три одновременно при инициализации мока, порядок приоритета останется тем же:24592460```python2461>>> order_mock = Mock(spec=Order, wraps=Order,2462...                   **{"get_value.side_effect": ["first"],2463...                      "get_value.return_value": "second"}2464...                   )2465...2466>>> order_mock.get_value()2467'first'2468>>> order_mock.get_value.side_effect = None2469>>> order_mock.get_value()2470'second'2471>>> order_mock.get_value.return_value = DEFAULT2472>>> order_mock.get_value()2473'third'2474```24752476Если [`side_effect`](https://python-all.ru/3.15/library/unittest.mock.html#unittest.mock.Mock.side_effect) исчерпан, порядок приоритета не приведёт к получению значения от последующих элементов. Вместо этого будет возбуждено исключение `StopIteration`.24772478```python2479>>> order_mock = Mock(spec=Order, wraps=Order)2480>>> order_mock.get_value.side_effect = ["first side effect value",2481...                                     "another side effect value"]2482>>> order_mock.get_value.return_value = "second"2483```24842485```python2486>>> order_mock.get_value()2487'first side effect value'2488>>> order_mock.get_value()2489'another side effect value'2490```24912492```python2493>>> order_mock.get_value()2494Traceback (most recent call last):2495 ...2496StopIteration2497```2498