HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>В тестировании очень популярен<strong>мокинг</strong>. Технически он похож на стабинг, и из-за этого их часто путают. Но все же они служат разным целям и используются в разных ситуациях. В этом уроке мы разберемся, что такое мокинг и зачем он нужен.</p>
1 <p>В тестировании очень популярен<strong>мокинг</strong>. Технически он похож на стабинг, и из-за этого их часто путают. Но все же они служат разным целям и используются в разных ситуациях. В этом уроке мы разберемся, что такое мокинг и зачем он нужен.</p>
2 <p>До этого момента мы рассматривали побочные эффекты как помеху тестирования нашей логики. Для их изоляции использовались либо стабы, либо прямое выключение логики в тестовой среде. После этого можно было спокойно проверять правильность работы функции.</p>
2 <p>До этого момента мы рассматривали побочные эффекты как помеху тестирования нашей логики. Для их изоляции использовались либо стабы, либо прямое выключение логики в тестовой среде. После этого можно было спокойно проверять правильность работы функции.</p>
3 <p>В некоторых ситуациях требуется кое-что другое. Иногда нам нужно не получить результат работы функции, а проверить, выполняет ли она нужное нам действие - например, шлет правильный HTTP-запрос с правильными параметрами.</p>
3 <p>В некоторых ситуациях требуется кое-что другое. Иногда нам нужно не получить результат работы функции, а проверить, выполняет ли она нужное нам действие - например, шлет правильный HTTP-запрос с правильными параметрами.</p>
4 <p>Для этого понадобятся моки. Они проверяют, как выполняется код.</p>
4 <p>Для этого понадобятся моки. Они проверяют, как выполняется код.</p>
5 <h2>HTTP</h2>
5 <h2>HTTP</h2>
6 <p>Начнем с такого фрагмента кода:</p>
6 <p>Начнем с такого фрагмента кода:</p>
7 <p>Отслеживание выполнения какого-то действия - это и есть<strong>мокинг</strong>. Мок проверяет, что какой-то код выполнился определенным образом. Это может быть вызов функции, HTTP-запрос и тому подобное.</p>
7 <p>Отслеживание выполнения какого-то действия - это и есть<strong>мокинг</strong>. Мок проверяет, что какой-то код выполнился определенным образом. Это может быть вызов функции, HTTP-запрос и тому подобное.</p>
8 <p>У мока две задачи:</p>
8 <p>У мока две задачи:</p>
9 <ul><li>Убедиться в том, что событие произошло - например, функция передала данные</li>
9 <ul><li>Убедиться в том, что событие произошло - например, функция передала данные</li>
10 <li>Отследить, каким конкретно образом оно произошло - функция передала конкретные данные</li>
10 <li>Отследить, каким конкретно образом оно произошло - функция передала конкретные данные</li>
11 </ul><p>Что дает нам такая проверка? В этом случае не очень много. Да, мы убеждаемся, что вызов был, но само по себе это еще ни о чем не говорит. В чем же тогда польза моков?</p>
11 </ul><p>Что дает нам такая проверка? В этом случае не очень много. Да, мы убеждаемся, что вызов был, но само по себе это еще ни о чем не говорит. В чем же тогда польза моков?</p>
12 <p>Представьте, что мы бы разрабатывали библиотеку PyGithub - ту самую, что выполняет запросы к GitHub API. Вся суть этой библиотеки в том, чтобы выполнить правильные запросы с правильными параметрами. Поэтому там нужно обязательно проверять выполнение запросов с указанием точных URL-адресов. Только в таком случае можно быть уверенными, что она выполняет верные запросы.</p>
12 <p>Представьте, что мы бы разрабатывали библиотеку PyGithub - ту самую, что выполняет запросы к GitHub API. Вся суть этой библиотеки в том, чтобы выполнить правильные запросы с правильными параметрами. Поэтому там нужно обязательно проверять выполнение запросов с указанием точных URL-адресов. Только в таком случае можно быть уверенными, что она выполняет верные запросы.</p>
13 <p>В этом ключевое отличие мока от стаба:</p>
13 <p>В этом ключевое отличие мока от стаба:</p>
14 <ul><li>Стаб устраняет побочный эффект, чтобы не мешать проверке результата работы кода - например, возврату данных из функции</li>
14 <ul><li>Стаб устраняет побочный эффект, чтобы не мешать проверке результата работы кода - например, возврату данных из функции</li>
15 <li>Мок фокусируется на том, как конкретно работает код, что он делает внутри</li>
15 <li>Мок фокусируется на том, как конкретно работает код, что он делает внутри</li>
16 </ul><p>При этом чисто технически мок и стаб создаются почти одинаково, за исключением того, что на мок вешают ожидания, проверяющие вызовы. Из-за этого моками часто называют стабы. Для себя всегда пытайтесь понять, о чем идет речь. Это важно, потому что от этого зависит фокус тестов.</p>
16 </ul><p>При этом чисто технически мок и стаб создаются почти одинаково, за исключением того, что на мок вешают ожидания, проверяющие вызовы. Из-за этого моками часто называют стабы. Для себя всегда пытайтесь понять, о чем идет речь. Это важно, потому что от этого зависит фокус тестов.</p>
17 <h2>Функции</h2>
17 <h2>Функции</h2>
18 <p>Моки довольно часто используют с функциями (методами). К примеру, они могут проверять:</p>
18 <p>Моки довольно часто используют с функциями (методами). К примеру, они могут проверять:</p>
19 <ul><li>Вызвана ли функция, сколько раз ее вызвали</li>
19 <ul><li>Вызвана ли функция, сколько раз ее вызвали</li>
20 <li>Какие аргументы переданы в функцию, сколько всего аргументов</li>
20 <li>Какие аргументы переданы в функцию, сколько всего аргументов</li>
21 <li>Что именно вернула функция</li>
21 <li>Что именно вернула функция</li>
22 </ul><p>Предположим, что мы хотим протестировать функцию for_each(). Она вызывает колбек для каждого элемента коллекции:</p>
22 </ul><p>Предположим, что мы хотим протестировать функцию for_each(). Она вызывает колбек для каждого элемента коллекции:</p>
23 <p>Эта функция ничего не возвращает, поэтому напрямую ее не протестировать.</p>
23 <p>Эта функция ничего не возвращает, поэтому напрямую ее не протестировать.</p>
24 <p>Можно попробовать сделать это с помощью моков. Проверим, что она вызывает переданный колбек и передает туда нужные значения. Сделаем это с помощью модуля<em>mock</em>, который входит в стандартную библиотеку Python как часть<em>unittest</em>:</p>
24 <p>Можно попробовать сделать это с помощью моков. Проверим, что она вызывает переданный колбек и передает туда нужные значения. Сделаем это с помощью модуля<em>mock</em>, который входит в стандартную библиотеку Python как часть<em>unittest</em>:</p>
25 <p>С помощью моков мы проверили, что функция была вызвана ровно три раза, и ей передавался новый элемент коллекции последовательно для каждого вызова.</p>
25 <p>С помощью моков мы проверили, что функция была вызвана ровно три раза, и ей передавался новый элемент коллекции последовательно для каждого вызова.</p>
26 <p>Можно сказать, что этот тест действительно проверяет работоспособность функции for_each(). Но можно сделать это проще, без мока и без завязки на внутреннее поведение. Для этого достаточно использовать замыкание:</p>
26 <p>Можно сказать, что этот тест действительно проверяет работоспособность функции for_each(). Но можно сделать это проще, без мока и без завязки на внутреннее поведение. Для этого достаточно использовать замыкание:</p>
27 <h2>Объекты</h2>
27 <h2>Объекты</h2>
28 <p>Кроме использования моков для тестирования функций, они также могут использоваться для тестирования объектов.</p>
28 <p>Кроме использования моков для тестирования функций, они также могут использоваться для тестирования объектов.</p>
29 <p>В тестировании объектов моки могут использоваться для имитации поведения объектов, от которых зависит тестируемый объект. Например, если объект A зависит от объекта B, то можно создать мок-объект для объекта B и использовать его в тестах объекта A. Это позволит тестировать объект A, не затрагивая объект B и его зависимости.</p>
29 <p>В тестировании объектов моки могут использоваться для имитации поведения объектов, от которых зависит тестируемый объект. Например, если объект A зависит от объекта B, то можно создать мок-объект для объекта B и использовать его в тестах объекта A. Это позволит тестировать объект A, не затрагивая объект B и его зависимости.</p>
30 <p>Еще он умеет оборачивать существующую реализацию:</p>
30 <p>Еще он умеет оборачивать существующую реализацию:</p>
31 <h2>Преимущества и недостатки</h2>
31 <h2>Преимущества и недостатки</h2>
32 <p>Существуют ситуации, в которых моки нужны, но все таки в большинстве ситуаций их нужно избегать. Моки слишком много знают о том, как работает код. Любой тест с моками из черного ящика превращается в прозрачный ящик.</p>
32 <p>Существуют ситуации, в которых моки нужны, но все таки в большинстве ситуаций их нужно избегать. Моки слишком много знают о том, как работает код. Любой тест с моками из черного ящика превращается в прозрачный ящик.</p>
33 <p>Повсеместное использование моков приводит к двум вещам:</p>
33 <p>Повсеместное использование моков приводит к двум вещам:</p>
34 <ul><li>После рефакторинга приходится переписывать тесты, даже если код работает правильно. Так происходит, потому что тесты завязаны на то, как конкретно работает код</li>
34 <ul><li>После рефакторинга приходится переписывать тесты, даже если код работает правильно. Так происходит, потому что тесты завязаны на то, как конкретно работает код</li>
35 <li>Код может перестать работать. При этом тесты будут проходить, потому что они сфокусированы не на результатах работы кода, а на его устройстве внутри</li>
35 <li>Код может перестать работать. При этом тесты будут проходить, потому что они сфокусированы не на результатах работы кода, а на его устройстве внутри</li>
36 </ul><p>Там, где возможно использование реального кода - используйте реальный. Там, где возможно убедиться в работе кода без моков - делайте это без моков.</p>
36 </ul><p>Там, где возможно использование реального кода - используйте реальный. Там, где возможно убедиться в работе кода без моков - делайте это без моков.</p>
37 <p>Излишний мокинг повышает стоимость поддержки тестов и делает их бесполезными. Идеальные тесты - тесты методом черного ящика.</p>
37 <p>Излишний мокинг повышает стоимость поддержки тестов и делает их бесполезными. Идеальные тесты - тесты методом черного ящика.</p>