> ✍️ О себе: Пишу боевые юнит-тесты для React уже 4 года в продакшене, а не для «todo-list». Знаю школы тестирования, прошёл путь от Enzyme до RTL — и создал свою библиотеку
shallowly. Пишу код вслепую в Neovim и уверен: времени «нет» только у тех, кто предпочитает кликать мышью в IDE вместо написания тестов.
Словарь терминов
-
Юнит (Unit) — наименьшая тестируемая часть приложения. В React это обычно компонент, хук или функция в изоляции
-
Shallow rendering — поверхностный рендеринг компонента без рендеринга его дочерних компонентов
-
Mock — имитация зависимости, которая заменяет реальную реализацию в тестах
-
TDD (Test-Driven Development) — разработка через тестирование, когда тест пишется до кода
-
CI/CD — автоматизированная система сборки и деплоя
Исповедь бывшего кликера
Когда-то мой чек-лист «готова ли фича» выглядел как молитва джуна: открыть браузер, нажать пару кнопок, убедиться, что в консоли нет красного цвета (желтое — это нормально, да?), и смело делать merge.
В те времена React был еще зеленым, Backbone уходил в архив, а модные парни на конференциях говорили про какое-то тестирование. Я слушал их как индеец — много слов, мало понимания.
Проект жил быстро, но баги плодились еще быстрее. Каждый хот-фикс тянул за собой новый хот-фикс, как матрешка багов. Я начал бояться рефакторинга сильнее, чем дантист боится собственных зубов.
Переломный момент настал ночью перед релизом. Один пропущенный null-чек положил всю систему авторизации. Пока я в 3 утра откатывал релиз, понял: так больше жить нельзя.
Эволюция подходов: как я перестал бояться и полюбил тесты
Этап 1: Скриншот-тестирование «на коленке»
Первым делом попробовал snapshot-тесты. Логика была простая: «Если diff не красный — значит все хорошо». Быстро понял, что это как охранять дом сигнализацией, которая срабатывает от пролетающей мухи. Поменял padding на 2px — тест красный. Исправил опечатку в тексте — тест красный. Добавил запятую — красный.
Этап 2: E2E через страдания
Потом открыл для себя Cypress. Казалось — вот оно, решение! Прогоняю весь пользовательский сценарий, имитирую клики, получаю уверенность.
Но оказалось, что E2E тесты как дорогая машина: выглядят круто, но постоянно ломаются, требуют ухода, и когда что-то не работает — фиг поймешь где проблема. Плюс ждать 10 минут результата теста — это как ждать загрузки интернета в 2003 году.
Этап 3: Юнит-тесты как просветление
И тут я понял истину: юнит-тесты это не про количество, а про качество жизни разработчика. Они:
-
Ловят очевидные ошибки еще до браузера (null-check привет!)
-
Дают смелость резать мертвый код без страха что-то сломать
-
Документируют намерения лучше любых комментариев
-
Работают молниеносно — фидбек за пару миллисекунд, а не минуты
Сейчас в нашем репозитории 3000+ тестов, а CI за 2–3 минуты говорит, можно ли деплоить. Да, писать тесты — «дорого», но постоянно чинить баги в сложном коде да еще и продакшене дороже в разы.
Типы тестирования: зоопарк подходов
Рассмотрим основные типы тестирования, чтобы понимать, откуда ноги растут. Кстати, интересный факт: если бы у тестирования был свой Оскар, то награда за лучшую мужскую роль досталась бы Кенту Беку за вклад в разработку через тестирование (TDD) в конце 90-х. Но давайте по порядку.
🧪 Юнит-тесты
Родоначальник: Кент Бек (да, он снова здесь) в рамках методологии экстремального программирования (XP) в конце 90-х.
Современные амбассадоры:
-
Мартин Фаулер, который до сих пор яростно спорит о том, что считать «юнитом»
-
Роберт (Боб) Мартин (Дядя Боб), который считает, что если у вас нет 100% покрытия, вы, вероятно, что-то упускаете
-
Стив Фримен (один из авторов «Growing Object-Oriented Software»), который знает о юнит-тестах всё и даже больше
-
Дэвид Хейнемейр Ханссон (DHH), который сначала ругал TDD, а потом полюбил его
Философия: Создавались как основа TDD (разработки через тестирование). Идея в том, чтобы проверять мельчайшие кирпичики кода в изоляции, как инженер проверяет шестерёнки перед сборкой механизма. Юниты — это про уверенность, что каждая функция работает как часы, даже если вокруг всё горит.
Что тестируют: Отдельные функции, компоненты в изоляции
Скорость: Молниеносно (миллисекунды)
Плюсы: Быстро, детерминированно, легко отлаживать
Минусы: Не видят проблем интеграции
// Пример юнит-теста test("Calculator сумма двух чисел", () => { const calc = new Calculator(); expect(calc.add(2, 3)).toBe(5); });
🔄 Интеграционные тесты
История: Появились как ответ на проблему «все тесты проходят, а продакшен падает». Впервые систематизированы Майклом Фезерсом в середине 2000-х.
Современные гуру:
-
Сэм Ньюмен, автор книги «Монилитный кризис» и ярый проповедник микросервисов
-
Мартин Фаулер, который считает, что если ваш интеграционный тест не падает хотя бы раз в неделю, вы, вероятно, тестируете не всё
-
Ибрагим Чешмелиоглу, автор «Testing JavaScript Applications», который знает о тестировании фронтенда всё
-
Сэнди Метц, которая умеет объяснять сложные концепции тестирования так, что даже менеджеры кивают
Философия: Родились из осознания, что юниты — это здорово, но код живёт не в вакууме. Интеграционные тесты проверяют, как шестерёнки крутятся вместе. Их цель — поймать проблемы на стыке модулей, когда один разработчик думал, что возвращает null, а другой ждал строку.
// Пример интеграционного теста test("Button должен вызывать onClick при клике", () => { const onClick = jest.fn(); const { getByText } = render(<button>Click me</button>); fireEvent.click(getByText("Click me")); expect(onClick).toHaveBeenCalledTimes(1); }); // да да для меня это интеграционный тест . Чуть позже раскажу почему.
Что тестируют: Взаимодействие между компонентами/модулями
Скорость: Средняя (секунды)
Плюсы: Видят проблемы интеграции, ближе к реальности
Минусы: Сложнее отлаживать, медленнее
🌐 E2E тесты
История: Зародились в эпоху мейнфреймов, но второе рождение получили с приходом веба. Селин Ласик (Selenium, 2004) — наш герой, который подарил нам все эти browser.click().
Современные гуру:
-
Гилен Дебелп (Gleb Bahmutov), который, кажется, может написать E2E-тест быстрее, чем вы успеете произнести «флакки-тест»
-
Андрей Симонов, создатель CodeceptJS, который доказал, что E2E-тесты могут быть не только медленными, но и быстрыми
-
Филипп Харитонов, автор Playwright, который заставил всех поверить, что стабильные E2E-тесты — это не миф
-
Пол Гросс (Paul Grosse), который умудряется тестировать даже самые сложные веб-приложения, не теряя рассудка
Философия: Это взгляд сверху на всю систему глазами пользователя. Создавались, чтобы убедиться, что путь от логина до чекаута не превратится в квест «найди баг». E2E-тесты — это как генеральная репетиция перед премьерой: всё должно работать как в жизни, даже если под капотом творится хаос.
Что тестируют: Полные пользовательские сценарии
Скорость: Медленно (минуты)
Плюсы: Максимально близко к реальности
Минусы: Хрупкие, медленные, сложные в отладке
Модели тестирования: философские школы и их гуру
Как говорил один мой знакомый тестировщик: «Есть два типа команд: те, кто следует моделям тестирования, и те, кто делает вид, что их не существует». Давайте познакомимся с основными подходами и их создателями.
Далее у нас есть методология тестирования которые определяют сколько и каких тестов должно быть.
🛕 Пирамида тестирования (классика)
Авторство: Майк Кан (Mike Cohn) в книге «Succeeding with Agile» (2009).
Интересный факт: Изначально пирамида была перевернута, но потом Майк одумался (или просто перевернул слайд, история умалчивает).
Современные амбассадоры:
-
Джеральд Вайнберг, который до сих пор учит нас, что «чем ниже, тем лучше»
-
Лиза Криспин, соавтор «Agile Testing», которая знает о пирамиде всё и даже больше
-
Джанет Грегори, которая умеет объяснить пирамиду тестирования так, что даже бизнес-аналитики начинают её использовать
-
Кент Бек, который, кажется, успел оставить свой след во всём, что связано с тестированием
🌐 E2E (мало) — как вишенка на торте 🔄 Интеграционные (средне) — кремовая начинка 🧪 Юнит-тесты (много) — прочное бисквитное основание
Философия: Чем ниже уровень — тем больше тестов. Они дешевле и быстрее. Это как диета: если перевернуть пирамиду, получится торт, который упадёт вам на голову при первой же попытке деплоя.
Когда использовать: Стабильные большие проекты, команды с опытом, которые понимают разницу между тестом и кликбейт-заголовком.
💎 Тестовый алмаз
История: Зародился в недрах микросервисных команд в начале 2010-х, когда разработчики устали объяснять, почему их сервисы не работают вместе, несмотря на зелёные тесты.
Современные амбассадоры:
-
Ник Тюн (Nick Tune), который рисует такие схемы, что хочется распечатать их как постер и повесить на стену с подписью «Вот как надо!»
-
Сэм Ньюмен, который, кажется, знает о микросервисах и их тестировании всё
-
Крис Ричардсон, автор «Microservices Patterns», который умеет объяснять сложные концепции простыми словами
-
Мартин Фаулер, который успел высказаться практически обо всём в мире разработки, включая и эту модель
🌐 E2E (мало) — потому что никто не любит ждать 🔄 Интеграционные (МНОГО) — вот где настоящая магия 🧪 Юнит-тесты (средне) — на всякий случай
Философия: Если юнит-тесты — это проверка каждой шестерёнки по отдельности, то интеграционные — это когда вы собираете велосипед и надеетесь, что он поедет. Акцент на реальные взаимодействия компонентов, потому что в реальном мире никто не живёт в вакууме (кроме, возможно, некоторых менеджеров).
Когда использовать: Микросервисы, сложная интеграция и когда хочется почувствовать себя повелителем распределённых систем.
🍦 Мороженое (антипаттерн)
История: Никто не «придумал» это специально, но стало мемом благодаря командам, которые в 2000-х годах полагались только на Selenium и молитвы.
Известные последователи:
-
Тот самый тимлид в вашей компании, который говорит: «У нас нет времени на юнит-тесты, давайте просто накрутим E2E»
-
Джо Армстронг (создатель Erlang), который как-то сказал: «Единственный способ отлаживать код — это добавлять операторы вывода»
-
Все, кто когда-либо говорил: «Да ладно, у нас же CI/CD, пусть сами тесты падают»
-
Легендарный «Петя из отдела тестирования», который до сих пор верит, что ручное тестирование — это будущее
🌐 E2E (МНОГО) — потому что кому нужны тесты, если можно просто нажать F5? 🔄 Интеграционные (мало) — случайно затесались 🧪 Юнит-тесты (почти нет) — «это же лишний код»
Философия: Строим дом с крыши. Выглядит сладко, пока не начнётся дождь багов. А когда начинается — все дружно удивляемся, почему же так медленно и ничего не работает.
Результат: Медленно, дорого, нестабильно. Но зато можно сказать, что у вас «полная тестовая документация» (из 2000 тестов, которые падают в случайном порядке).
Кто так делает: Те, кто считает, что «тестирование — это когда QA посидел, понажимал кнопочки и сказал, что всё ок».
🏆 Тестовый трофей (Kent C. Dodds, ~2017)
🌐 E2E 🔄 Интеграционные (основа) 🧪 Юнит-тесты ⚡ Статический анализ
Контекст: Появился как ответ на сложности тестирования React-приложений. Кент, кстати, до сих пор уверяет, что это не он придумал, а всего лишь «систематизировал».
Ключевые адепты:
-
Кент С. Доддс (Kent C. Dodds), который, кажется, может написать тест быстрее, чем вы успеете сказать «почему это не работает?»
-
Мишель Титус (Michelle Titus), которая доказывает, что тестирование React может быть не только эффективным, но и приятным
-
Райан Флоренс (Ryan Florence), создатель React Router, который знает о тестировании React-приложений всё (и даже немного больше)
-
Марко Полетто (Marco Piraccini), который умеет объяснить, почему статический анализ — это не просто мода, а must-have
Философия: «Тестируй как пользователь» + акцент на интеграционные
Инструменты: React Testing Library
🧊 Тестовый куб (для больших систем)
Автор: Брайан Оккенфельс (Brian Okken), автор книги «Python Testing with pytest».
Фишка: Когда двумерных моделей стало мало, пришлось добавить третье измерение. Типичная история для программистов.
Многомерная модель с тремя осями:
-
Что: компоненты, контракты, интеграции
-
Как: юнит, e2e, нагрузочные тесты
-
Где: локально, CI, staging, production
Когда использовать: Энтерпрайз, микросервисы, большие команды
Школы юнит-тестирования
теперь почему я говорю что React Testing Library это не юнит тесты.
📚 Классическая школа (Detroit School)
Гуру:
-
Кент Бек, который, кажется, успел основать всё, что можно
-
Мартин Фаулер, который умеет объяснить, почему это работает
-
Сэнди Метц, которая знает о тестировании объектов всё
-
Дэвид Хейнемейр Ханссон (DHH), который сначала ругал TDD, а потом полюбил его
Принципы:
-
Тестируй поведение, а не реализацию
-
Минимум моков, максимум реальных объектов
-
Тест должен быть понятен без изучения кода
🏭 Лондонская школа (Mockist School)
Гуру:
-
Стив Фримен, соавтор «Growing Object-Oriented Software»
-
Нейт Шугармен, который умеет объяснить, зачем вообще нужны моки
-
Мартин Фаулер, который успел высказаться и на эту тему
Принципы:
-
Тотальная изоляция через моки
-
Тестируй взаимодействия между объектами
-
Каждый тест проверяет одну единицу
Тут идет различие что считать юнитом и в каком окружении он должен быть. Мое мнение что юнит это компонент в изоляции от окружающего мира как можно зависимостей особено от библиотек которые мы используем в этом юните.
Так что же насчёт Мартина Фаулера?
Когда речь заходит о тестировании, все почему-то ждут, что Мартин Фаулер даст однозначный ответ. Но он, как настоящий мудрец, предпочитает не вставать ни на чью сторону, оставляя место для манёвра:
-
Прагматичный баланс — он не фанатик ни одной из школ, а скорее адепт здравого смысла. «Тестируйте так, чтобы было эффективно, а не чтобы угодить гуру» — вот его негласный девиз.
-
Рефакторинг — наше всё — его подход к тестированию неотделим от рефакторинга. Если ваши тесты не дают вам уверенности при рефакторинге, значит, вы делаете что-то не так. Или делаете это с закрытыми глазами.
-
Догмам — нет! — Фаулера раздражают священные войны между адептами разных подходов. «Гибкость, а не фанатизм» — мог бы быть его девиз, если бы он любил девизы.
-
Unit-тесты как страховка — в своей настольной книге «Refactoring» он делает ставку на unit-тесты, но без фанатизма. Примерно как с кофе: одна чашка бодрит, десять — вызывают тремор.
-
Реализм превыше всего — он признаёт, что в реальных проектах идеальная пирамида тестирования часто превращается в нечто среднее между алмазом и снежинкой, и это нормально. Главное — понимать, зачем вы это делаете.
Если бы Фаулеру пришлось выбирать модель тестирования, он, вероятно, выбрал бы «пирамиду с человеческим лицом» — с акцентом на unit-тесты для рефакторинга и достаточным количеством интеграционных тестов, чтобы не краснеть перед продакшеном. Но он бы точно предупредил: «Любая модель — это всего лишь модель. Не путайте карту с местностью, а тесты — с реальным кодом».
Практические выводы
После 4 лет боевого тестирования вот что я понял:
-
Начинайте с юнитов — они дают максимум пользы за минимум времени
-
Пирамида работает для большинства проектов, но не бойтесь адаптировать
-
Качество важнее количества — лучше 10 хороших тестов, чем 100 плохих
-
Тесты — это инвестиция — но тесты не должны быть дорогими, потом окупается с лихвой
Рекомендуемая литература
Книги на русском
-
Мартин Фаулер, «Рефакторинг. Улучшение существующего кода» — классика о тестировании как основе для безопасного рефакторинга.
-
Кент Бек, «Разработка через тестирование» — манифест TDD от его создателя.
-
Стив Фримен, Рой Ошероув, «Тестирование JavaScript-приложений» — про тестирование в экосистеме JavaScript.
-
Виктор Сапаров, «Тестирование Дот Ком» — отличное введение в тестирование от российского автора.
-
Сергей Аверин, «Тестирование программного обеспечения» — базовый учебник по тестированию.
Книги на английском
-
Robert C. Martin, «Clean Code» — главы про тестирование обязательны к прочтению.
-
Kent Beck, «Test-Driven Development: By Example» — must-read для понимания TDD.
-
Luca Mezzalira, «Frontend Architecture for Design Systems» — про тестирование в современных фронтенд-архитектурах.
-
Eric Elliott, «Composing Software» — о композиционном подходе к тестированию.
Статьи и онлайн-ресурсы
На русском:
-
Пирамида тестирования на практике — разбор на Хабр
-
Юнит-тесты: введение — отличный учебник на learn.javascript.ru
-
Тестирование React-приложений — официальная документация React
На английском:
-
The Testing Trophy and Testing Classifications — современный взгляд на классификацию тестов
-
TestPyramid — классическая статья Мартина Фаулера
-
React Testing Examples — примеры тестирования React-компонентов
-
Testing Library — принципы тестирования от создателей React Testing Library
Эти ресурсы помогут не только разобраться в «как» и «почему» тестирования, но и покажут разные подходы и философии, стоящие за разными школами тестирования.
В следующих частях разберем, почему юнит-тесты — это турбо-режим для разработки, как TDD меняет подход к коду, и почему я создал библиотеку shallowly вместо того, чтобы мучиться с RTL.
Следующая статья: «Почему именно юнит-тесты: от TDD до архитектуры компонентов»
P.S. Если вы до сих пор тестируете только через браузер — не расстраивайтесь. Мы все когда-то были такими. Главное — начать. А с этими книгами вы точно поймете, что к чему в мире тестирования.
ссылка на оригинал статьи https://habr.com/ru/articles/921152/
Добавить комментарий