Как тестировать то, чего еще не существует? MOCK, STUB, FAKE — разница, применение и подводные камни
Представьте: проект движется вперед, разработка кипит, сроки поджимают… но вот незадача — сервисы, от которых зависит тестирование, либо не готовы, либо ведут себя непредсказуемо. В худшем случае их вообще нет.
Пауза? Нет, не вариант.
Опытные разработчики и тестировщики давно нашли способ тестировать даже то, чего еще нет. Встречайте трех героев невидимого фронта: MOCK, STUB и FAKE. Разбираемся, кто есть кто и как их правильно использовать, со Станиславом Беленовым, тестировщиком на проекте в SkillStaff.
⭐ Чек-лист в конце статьи поможет определиться с выбором заглушки для ваших задач.
Как работают заглушки
Заглушки — это специальные объекты, с помощью которых вы можете проверить программное обеспечение без готового кода, базы данных или даже сценариев, которые предусмотрены аналитикой, но невозможны к исполнению на тестовой среде.
Я использую для тестирования три вида заглушек — MOCK, STUB и FAKE. Они прекрасно имитируют работу недостающих компонентов и подходят под разные задачи, в том числе пригодятся разработчикам.
Где полезны заглушки
✔ Проверить корректность вызова методов с правильными параметрами и в нужном порядке
✔ Протестировать новые изменения, не влияя на существующий функционал.
✔ Проектировать проекты и начинать тестирование, не дожидаясь доработок других систем.
✔ Проводить автоматизированные тесты в CI/CD пайплайнах.
Разберем каждый объект подробнее.
STUB
STUB — упрощенная версия объекта, которая заменяет реальный компонент системы на время тестирования. Это минимальная версия объекта, которая просто возвращает фиксированные ответы. Стаб не выполняет логику, не отслеживает вызовы и не хранит состояние — его задача только в одном: быстро дать предсказуемый результат.
📌 Стабы решают несколько ключевых проблем:
1. Изоляция тестируемого кода — помогает тестировать логику, не завися от реальных сервисов.
2. Упрощение тестирования — STUB возвращает предопределенные данные, убирая сложность настройки тестов.
3. Ускорение тестов — выполняется мгновенно, без обращений к базе данных, API и другим внешним ресурсам.
4. Тестирование крайних случаев — позволяет легко эмулировать ошибки и нестандартные ответы.
Как это выглядит на практике:
Допустим, у вас есть метод, который получает данные о пользователе из базы данных. Вместо подключения к реальной базе, вы настраиваете стаб.
Как создать STUB
1. Определите, что подменять
Выберите интерфейс или класс, который нужно заменить заглушкой, чтобы контролировать его поведение в тестах.
2. Создайте реализацию
Напишите класс, который реализует этот интерфейс.
⚠ Ограничения:
STUB возвращает заранее заданный ответ, но не эмулирует сложное поведение системы. Если зависимость ведет себя нестандартно, STUB этого не покажет.
Слишком примитивные стабы могут привести к тому, что тесты перестанут отражать реальное поведение системы.
FAKE
FAKE — это объект с упрощенной, но рабочей реализацией. Он выполняет некоторые функции настоящего объекта, но не предназначен для продакшна. Например, вместо реальной базы данных можно использовать FAKE-объект, который хранит данные в памяти.
📌 Фейки решают несколько ключевых проблем:
1. Эмуляция сложного поведения — позволяет тестировать код в условиях, близких к реальным, например, при работе с базами данных или внешними API.
2. Контроль состояния — FAKE-объекты могут запоминать, какие операции с ними выполнялись, что упрощает тестирование.
3. Оптимизация тестов — снижает затраты на тестирование, так как FAKE-объекты не требуют реальных ресурсов (серверов, сетевых соединений и т. д.).
Как это выглядит на практике:
Допустим, у нас есть система, которая отправляет электронные письма. Вместо использования реального сервера, мы можем создать FAKE, который будет имитировать отправку писем и хранить их в памяти для последующей проверки.
⚠ Ограничения FAKE
Если поведение фейков не соответствует реальной системе, тесты могут пропускать ошибки, которые проявятся уже в бою. К тому же FAKE-объекты зависят от внутренней реализации кода, и любое изменение может потребовать переделки тестов.
MOCK
MOCK — это вершина контроля. Мок позволяет проверять взаимодействие между компонентами. Он может не только возвращать заданные значения, как STUB, но и отслеживать, как и сколько раз его методы были вызваны.
📌 MOCK'и решают несколько ключевых проблем:
- Контроль поведения зависимостей — можно задать ожидаемое поведение объекта и проверить, как код реагирует на разные сценарии.
- Более точно тестировать логику обработки асинхронных операций — можно эмулировать задержки, ошибки или успешные ответы.
- Отсутствие зависимости от внешних ресурсов — больше никаких падений тестов из-за недоступных баз данных или API.
- Ускорение тестов — мокированные тесты выполняются быстрее, потому что не тратят время на запросы к внешним системам.
Как это выглядит на практике:
Предположим, у вас есть система уведомлений, которая отправляет уведомления асинхронно.
Для создания моков можно использовать такие библиотеки как unittest.mock в Python или Mockito в Java. Для создания актуальных и полных моков необходимо четко и полно изучить аналитику, чтобы знать какие методы должны быть вызваны. Для каждого из этих методов необходимо знать возвращаемые значения.
⚠ Ограничения
- Может давать ложное ощущение работоспособности. Если MOCK настроен неправильно, тесты могут проходить, но код в продакшене работать некорректно.
- Высокая связанность с реализацией. Тесты с MOCK зависят от конкретного кода, и при его изменении потребуется обновлять моки.