Тестовая пирамида: сколько каких тестов нужно проекту
Универсальной формулы вроде 70% unit-тестов и 10% end-to-end не существует. Разбираем, как распределять проверки по уровням, считать стоимость тестов и понять, где пирамида перестаёт работать.

Команда может иметь 2 000 тестов и всё равно ловить критические ошибки после релиза, если большинство проверок — медленные end-to-end-сценарии, а бизнес-правила почти не покрыты быстрыми тестами. Тестовая пирамида помогает распределить проверки по стоимости и скорости, но не задаёт магическое соотношение. Ниже — практическая схема для проекта, где нужно решить, сколько unit-, интеграционных, контрактных и end-to-end-тестов поддерживать.
Пирамида — это ограничение стоимости, а не процентная норма
Классическая модель состоит из широкого основания быстрых unit-тестов, среднего слоя интеграционных проверок и небольшой вершины end-to-end-тестов. Чем выше тест находится в пирамиде, тем больше компонентов он затрагивает, тем дольше выполняется и тем больше причин для случайного падения.
Поэтому вопрос «каких тестов должно быть 70%» поставлен неправильно. Считать нужно не только количество файлов или тестовых методов, но и время прогона, стоимость диагностики и риск, который закрывает каждый уровень.
Хорошая пирамида — это не красивое соотношение типов тестов, а такой набор проверок, при котором большинство ошибок ловится до дорогого сценария через пользовательский интерфейс.
Тестовая пирамида — модель распределения автоматизированных проверок по уровням: от локальных и быстрых к широким и дорогим. Это эвристика, а не стандарт и не обязательная метрика качества.
Какие уровни считать отдельно
Unit-тесты: правила и преобразования
Unit-тест проверяет небольшую часть кода изолированно: функцию расчёта, валидатор, обработчик состояния, преобразование данных. Такие тесты должны составлять основную массу набора там, где в системе много бизнес-логики.
Хороший кандидат для unit-теста — расчёт скидки с несколькими условиями, проверка допустимого статуса заказа или разбор входного документа. Плохой кандидат — тест, который поднимает базу данных, HTTP-сервер и очередь только ради проверки одной ветки.
Unit-тесты дешевы на запуске, но не доказывают, что модули правильно соединены. Изолированная функция может проходить проверку, а реальный SQL-запрос — падать из-за другой схемы данных.
Интеграционные тесты: реальные границы
Этот слой проверяет взаимодействие нескольких компонентов: приложения с PostgreSQL, Redis, брокером сообщений или внешним HTTP-сервисом. Здесь важен не интерфейс, а фактический протокол обмена и поведение инфраструктуры.
Интеграционные тесты нужны там, где ошибка в конфигурации или сериализации дороже, чем несколько минут прогона. Их должно быть меньше, чем unit-тестов, но нельзя заменять ими все проверки: при падении такого теста причина часто находится в миграции, контейнере, данных или окружении.
Контрактные тесты: согласованный формат между сервисами
Контрактный тест фиксирует договорённость между потребителем и поставщиком API: обязательные поля, типы, коды ответа и допустимое поведение. Он полезен в микросервисной системе, где команды выпускаются независимо.
Такой тест не заменяет интеграцию и не проверяет весь пользовательский сценарий. Его задача уже: обнаружить изменение API до того, как новая версия поставщика сломает потребителя.
End-to-end: путь пользователя от начала до результата
End-to-end-тест проходит через систему так, как это делает пользователь: открывает страницу или вызывает публичный интерфейс, создаёт сущность, оплачивает заказ, получает результат. Эти проверки закрывают максимальное расстояние между кодом и бизнес-операцией.
Цена — медленный прогон, сложная подготовка данных, нестабильность браузера и трудная диагностика. Один такой тест может подтвердить больше, чем десятки unit-тестов, но при падении не всегда сразу понятно, сломался ли интерфейс, авторизация, база или тестовые данные.
Сколько тестов закладывать на практике
Начните не с процентов, а с критических пользовательских потоков и структуры кода. Для типичного веб-сервиса разумна следующая стартовая гипотеза:
- основной объём — unit-тесты для бизнес-правил и преобразований;
- интеграционные тесты — для каждой важной границы с базой, очередью или внешним сервисом;
- контрактные тесты — для API, которыми владеют разные команды или релизные циклы;
- end-to-end — только для критических путей: вход, оформление заказа, оплата, выдача ключевого результата;
- ручные проверки — для визуальных деталей, исследовательских сценариев и функций, которые ещё часто меняются.
В качестве ориентировочной стартовой пропорции можно взять 60–80% unit-тестов, 15–30% интеграционных и контрактных проверок и 5–10% end-to-end. Это не норматив. Если приложение почти не содержит логики и в основном связывает внешние сервисы, доля интеграционных тестов будет выше. Если продукт — сложный расчётный движок, основание пирамиды должно быть значительно шире.
| Уровень | Что проверяет | Когда запускать | Основная цена |
|---|---|---|---|
| Unit | Локальное правило или модуль | На каждый commit и pull request | Не ловит ошибки соединения компонентов |
| Интеграционный | Связь приложения с реальной зависимостью | В pull request или отдельном CI-этапе | Среда, данные и диагностика |
| Контрактный | Совместимость API между участниками | До публикации новой версии сервиса | Поддержка контрактов и версий |
| End-to-end | Критический путь пользователя целиком | После сборки и перед релизом | Время, нестабильность, сложный разбор |
Как выбрать пропорцию для конкретного проекта
Сначала посчитайте не тесты, а риски
Составьте список операций, отказ которых приводит к потере денег, данных или доступа. Для каждой операции укажите место, где чаще всего возникает ошибка: алгоритм, база, API, браузер или инфраструктура. Затем назначьте проверку на том уровне, где дефект можно обнаружить дешевле всего.
Например, правило начисления бонусов должно иметь набор unit-тестов с граничными значениями. Создание записи в PostgreSQL требует интеграционной проверки. Совместимость формата между сервисами закрывает контрактный тест. Один end-to-end-сценарий подтверждает, что пользователь действительно может пройти путь от корзины до результата.
Измеряйте время и стабильность
Для каждого уровня полезно собирать четыре показателя:
- время полного прогона и время обратной связи для разработчика;
- долю падений, вызванных дефектом, а не окружением или тестовыми данными;
- количество дефектов, найденных до и после релиза;
- среднее время от падения до понятного диагноза.
Если end-to-end-набор работает 50 минут и часто падает из-за таймаутов, это не повод механически удалить его. Разделите сценарии на критические и вспомогательные, уберите дублирование с интеграционными тестами и проверьте, можно ли перенести часть проверок на более низкий уровень.
Где классическая пирамида ломается
Пирамида хуже описывает системы, в которых основной риск находится не в локальной логике. Для мобильного приложения с большим количеством разрешений, реального устройства и фоновых режимов потребуется больше проверок на устройстве. Для data pipeline важнее тесты схемы, качества данных и совместимости наборов, чем имитация кликов в браузере.
Есть и другие границы:
- если unit-тесты проверяют только getters и setters, большая доля таких тестов создаёт видимость покрытия;
- если интеграционные тесты используют исключительно моки, они могут не обнаружить несовместимость с настоящей базой или API;
- если end-to-end-сценарии дублируют каждую ветку бизнес-логики, CI становится медленным и хрупким;
- если тестовые данные общие для всех запусков, параллельный CI начинает влиять сам на себя;
- если контракт не версионируется, контрактный тест фиксирует прошлое поведение и мешает безопасному изменению API.
Инвалидация тестовых данных и стратегия моков — отдельные темы; здесь важно лишь то, что они напрямую влияют на стабильность верхних уровней.
Что ревьюить в тестовом наборе
На ревью смотрите не на голое покрытие строк, а на связь между тестом и риском. Полезные формулировки замечаний выглядят конкретно:
- «Эта проверка повторяет сценарий, уже закрытый интеграционным тестом, но запускается через браузер. Можно оставить один smoke-сценарий, а остальные ветки перенести ниже».
- «В тесте нет проверки поведения при пустом ответе внешнего сервиса. Это отдельная ветка бизнес-логики, её лучше покрыть быстрым unit-тестом».
- «Тест зависит от общей записи в базе и может падать при параллельном запуске. Нужны изолированные данные или явная очистка».
- «Проверяется только код ответа, но не обязательные поля контракта. Изменение схемы может пройти незамеченным».
Покрытие строк можно использовать как сигнал, но не как цель. Рост процента не означает рост защищённости, если тесты не проверяют отказные и граничные сценарии.
Что делать дальше
Возьмите один критический поток и разложите его на уровни: правила — в unit-тесты, реальные соединения — в интеграционные, границы сервисов — в контрактные, один полный путь — в end-to-end. Затем измерьте время CI и долю нестабильных падений за несколько запусков, а не по одному красному прогону.
После этого настройте правило для новых изменений: новый бизнес-риск получает самый дешёвый подходящий тест, а не автоматически ещё один браузерный сценарий. В CI отдельно показывайте быстрый набор для обратной связи и полный набор перед релизом. Через несколько недель сравните, какие дефекты дошли до продакшена и на каком уровне их можно было поймать раньше.
Универсальный ассистент: Обычный чат: тексты, идеи, разбор, перевод, расчёты.
Спросить за 8 ₽Источники: The Practical Test Pyramid, Just Say No to More End-to-End Tests
Частые вопросы
Есть ли правильное соотношение unit-, интеграционных и end-to-end-тестов?
Нужно ли писать end-to-end-тест для каждой функции?
Что делать, если end-to-end-тесты постоянно падают?
Работает ли эта модель для другого языка или фреймворка?
Можно ли заменить интеграционные тесты моками?
Что важнее: покрытие строк или количество тестов?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.