Тестовая Пирамида — Ложь (и Что Делать Вместо Этого). Начало
Автор оригинала: Milan Jovanović
Наверное, никогда мои проекты не имели канонической тестовой пирамиды, как на рисунке ниже. Широкое основание модульных тестов, узкое середина интеграционных тестов, крошечный кусочек сквозных тестов на вершине. Я согласно кивал на конференциях, но делал по-своему.
Откуда взялась пирамида
Пирамида была популяризирована Майком Коном в 2009 году, когда интеграционные тесты означали общий сервер БД, нестабильный CI и 20-минутные сборки. Модульные тесты с моками были прагматичным компромиссом.
Этот мир ушёл в прошлое. С помощью Testcontainers можно быстро запустить PostgreSQL, Redis и RabbitMQ в новом контейнере для каждого тестового класса. Aspire Test Host идёт ещё дальше, подключая весь граф вашего приложения. Аргумент о том, что реальные зависимости слишком затратны, по сути, больше не актуален. Но рекомендации не обновились.
Ошибка, которая меня убедила
Пару лет назад у меня был сервис с 94% покрытием модульными тестами. Все тесты были «зелеными». Но в один прекрасный день пользователь сообщил, что удаление учётной записи на самом деле не приводит к удалению его данных. Метод был проще некуда:
public async Task Handle(DeleteAccountCommand command, CancellationToken ct)
{
var account = await _repo.GetByIdAsync(command.AccountId, ct);
account.MarkAsDeleted();
}
Да, в нём забыли вызвать
SaveChangesAsync(). И тест для этого случая просто не был написан. Можно проверить, был ли вызван SaveChangesAsync в методе с помощью мока. Но в кодовой базе, где этот тест — один из сотен тестов обработчиков, каждый со своей настройкой мока и своим списком проверок, про это просто забыли. И покрытие тестами показывало, что всё в порядке. Один интеграционный тест с реальной БД обнаружил бы это в миг. В этом суть: чем меньше инвариантов ваш стиль тестирования заставляет вас запоминать, тем меньше ошибок проскальзывает.
В чём на самом деле хороши модульные тесты
Модульные тесты оправдывают себя, когда логика нетривиальна, чиста (без операций ввода-вывода, без асинхронности, без случайности) и сложна для проверки от начала до конца. Это вариантов кода вроде объектов-значений и сложных моделей домена, расчётов цен и налогов, парсеров, мапперов, сериализаторов и т.п.
Заметили, чего нет в этом списке? Сервисов, обработчиков, контроллеров, репозиториев, инфраструктуры. Они находятся на стыке модулей, и именно в этом стыке и кроются настоящие ошибки.
Что же делать вместо этого?
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-test-pyramid-is-a-lie-and-what-i-do-instead
