Как frontend-разработчик, вы проводите большую часть времени, создавая компоненты. Кнопка, поле формы, панель навигации, целая страница: в современном пользовательском интерфейсе каждый элемент является компонентом. Каждый из них рендерится по-разному в зависимости от переданных пропсов и состояния, а это значит, что у каждого есть множество возможных вариаций, которые нужно учесть.
Компонентное тестирование — это способ проверить, что эти вариации работают и рендерятся корректно, по одному компоненту за раз, без запуска всего приложения. Оно рендерит компонент в реальном браузере, позволяет симулировать действия пользователя и проверять, что компонент реагирует так, как задумано.
В этом руководстве объясняется, что такое компонентное тестирование, чем оно отличается от других видов тестов, которые вы можете писать, какие методы и инструменты при этом используются, а также с чего начать.
Попробуйте компонентное тестирование со Storybook »
Компонентное тестирование — это часть комплексной стратегии тестирования frontend. О том, как оно сочетается с модульным (unit), визуальным, доступным (accessibility) тестированием и сквозным (end-to-end) тестированием, читайте в руководстве по frontend-тестированию от Chromatic.
- Что такое компонентное тестирование. Где компонентное тестирование находится в цикле разработки. Основные характеристики компонентного тестирования
- Где компонентное тестирование находится в цикле разработки
- Основные характеристики компонентного тестирования
- Почему компонентное тестирование важно
- Распространенные методы компонентного тестирования
- Инструменты для компонентного тестирования
- Пример: тестирование компонента в Storybook 1. Тест рендеринга 2. Интерактивный тест 3. Тест с моками и шпионами
- 1. Тест рендеринга
- 2. Интерактивный тест
- 3. Тест с моками и шпионами
- Компонентное тестирование против модульного тестирования
- Компонентное тестирование против интеграционного тестирования
- Компонентное тестирование против сквозного тестирования
- Компонентное тестирование в эпоху ИИ-агентов
- Часто задаваемые вопросы. Кто обычно проводит компонентное тестирование? Как еще называется компонентное тестирование? Зачем использовать компонентное тестирование? Является ли компонентное тестирование тем же самым, что и модульное тестирование? Заменяют ли компонентные тесты сквозные тесты?
- Кто обычно проводит компонентное тестирование?
- Как еще называется компонентное тестирование?
- Зачем использовать компонентное тестирование?
- Является ли компонентное тестирование тем же самым, что и модульное тестирование?
- Заменяют ли компонентные тесты сквозные тесты?
Что такое компонентное тестирование
Компонентный тест рендерит отдельный UI-компонент в реальном браузере, изолированно от остального приложения. После рендеринга тест может взаимодействовать с компонентом так, как это делал бы пользователь, и проверять реакцию компонента.
0:00
/0:08
Входные данные компонента, проходящие визуальное тестирование внутри самого отрендеренного компонента.
Отличительной особенностью компонентного тестирования является то, что оно объединяет сильные стороны, обычно разделяемые между другими типами тестов. Подобно сквозному тесту (E2E), оно обеспечивает высокую точность, выполняясь в реальном браузере и имитируя реальное поведение пользователя. Подобно модульному тесту (unit), оно проверяет отдельную часть интерфейса изолированно и может проникать в реализацию для подделки (mock) данных или управления зависимостями. Именно эта комбинация делает его мощным средством проверки функционального поведения вашего интерфейса.
Где компонентное тестирование находится в цикле разработки
Полезно подумать о том, что именно вы тестируете. Атомарный дизайн, ментальная модель, популяризированная Брэдом Фростом (Brad Frost), описывает пользовательские интерфейсы как иерархию компонентов, возрастающих по сложности — от атомов вроде кнопок и полей ввода до молекул и организмов, через шаблоны и полностраничные компоненты. Компонентное тестирование применяется на каждом уровне этой иерархии: вы можете протестировать один атом изолированно, или составной организм, или весь компонент уровня страницы.
Поскольку компоненты — это то, что frontend-разработчики создают целыми днями, компонентное тестирование естественным образом происходит на ранних этапах и часто в процессе разработки. Основная задача разработчика — выполнить функциональные требования к фиче. Компонентные тесты (наряду с модульными) отвечают именно на этот вопрос, обеспечивая при этом самую быструю обратную связь. В хорошо организованном процессе тестирования компонентные и модульные тесты позволяют убедиться, что компонент рендерится в браузере и ведет себя должным образом. Как только фича проходит эти базовые тесты, вы добавляете проверку доступности (accessibility), внешнего вида и, наконец, сквозное тестирование, которое подтверждает, что фича интегрирована с остальной частью приложения.
Практический результат заключается в том, что компонентное тестирование — это не рутинная обязанность, добавленная в самом конце. Вы пишете компонент, рендерите его в различных состояниях, чтобы увидеть свою работу, и эти же состояния становятся тестами, доказывающими его соответствие требованиям.
Узнайте больше о том, какое место занимает компонентное тестирование в цикле frontend-разработки, в статье Chromatic.
Руководство по frontend-тестированию
Мы изучили десятки команд, чтобы выяснить, какие стратегии frontend-тестирования действительно работают. Это поможет вам создать прагматичную стратегию тестирования и избежать типичных ловушек.
Основные характеристики компонентного тестирования
- Изоляция. Компонент тестируется сам по себе, отдельно от остального приложения. Это одновременно и сильная сторона, и ограничение компонентного тестирования: вы получаете быстрые, сфокусированные, надежные тесты ценой того, что не проверяете, как вся система работает в сборе.
- Область действия (Scope). Компонентный тест может охватывать что угодно: от одного маленького компонента до крупного компонента уровня страницы. Чем выше вы поднимаетесь по иерархии, тем больше тест напоминает сквозной (E2E) тест.
- Среда. Компонентные тесты выполняются в реальном браузере, а не в симулируемой или headless DOM-эмуляции. Запуск в реальном браузере означает, что тест использует те же механизмы рендеринга, верстки и API, что и ваши пользователи, что дает больше уверенности, чем эмулированные среды.
- Ответственность. Компонентные тесты обычно пишутся и поддерживаются frontend-разработчиками, создающими компоненты, в рамках их обычного рабочего процесса разработки, а не передаются отдельной команде QA. Продакт-менеджеры и дизайнеры также обычно являются ключевыми участниками и частью процесса тестирования.
Почему компонентное тестирование важно
Тестирование покрытия UI ставит перед выбором. Сквозные (E2E) тесты дают наибольшую уверенность, так как имитируют реальное поведение пользователя в настоящем браузере, но они медленные, нестабильные (flaky), дорогие в настройке и их трудно перевести в определенные состояния интерфейса. Модульные тесты дешевы в написании и выполнении, так как запускаются против эмулированного DOM, но они мало что говорят о том, действительно ли интерфейс работает в настоящем браузере. Команды, пытающиеся обнаружить регрессии UI, оказываются зажаты между этими двумя вариантами.
Компонентные тесты разрешают эту дилемму, занимая промежуточное положение: подобно сквозным тестам, они выполняются в реальном браузере, но при этом достаточно малы, быстры и стабильны, чтобы сосуществовать с модульными тестами. Это делает их естественным выбором для большинства ваших UI-тестов, в то время как сквозные тесты зарезервированы для небольшого числа критических сценариев.
Практическая выгода: компонентные тесты позволяют быстро и надежно достичь состояний интерфейса, которые действительно сложно вызвать при полноценном сквозном прогоне — состояния загрузки, состояния ошибки, пустые состояния, сбои валидации форм. Вы охватываете широкий спектр состояний, в которых могут находиться ваши компоненты, в то время как небольшое число сквозных тестов покрывает критические успешные сценарии (happy paths).
Подробнее о том, почему команда Storybook считает компонентное тестирование будущим тестирования пользовательских интерфейсов, читайте в статье Компонентное тестирование в Storybook.
0:00
/0:13
Интерактивный тест, управляющий компонентом посредством клика, с успешным прохождением проверки.
Распространенные методы компонентного тестирования
На практике при тестировании интерфейсных компонентов обычно используется несколько взаимодополняющих методик, которые часто применяются в комплексе для одного и того же компонента:
- Тестирование рендеринга. Самый простой метод. Тест, который отрисовывает компонент в заданном состоянии и проходит успешно, если рендеринг происходит без ошибок, представляет собой дымовой тест (smoke test) — то, что в Storybook называют тестом рендеринга. Несмотря на свою простоту, он выявляет удивительно много проблем, и вы зачастую получаете его бесплатно, просто определив состояния, в которых может находиться ваш компонент.
- Интерактивное тестирование. Идя дальше, вы симулируете поведение пользователя, такое как клики, ввод текста и выбор элементов, и проверяете, что компонент реагирует правильно. Именно так тестируются компоненты с состоянием: открытие диалогового окна, отправка формы, переключение элемента управления и проверка результата.
- Мокирование и шпионы (mocking and spying). Поскольку тесты компонентов выполняют компонент в изоляции, вы можете подделывать данные, сетевые запросы и зависимости, чтобы перевести компонент в определенные состояния (индикатор загрузки, ошибка 404, пустой список), а также использовать шпионы для проверки правильности вызова функций.
В совокупности эти методы позволяют достичь практически любого состояния пользовательского интерфейса и проверить как внешний вид компонента, так и его поведение.
Описанные выше методики — это то, что вы делаете; инструменты, приведенные ниже — это то, чем вы это делаете. Они не соотносятся один к одному, поскольку большинство инструментов тестирования компонентов поддерживают несколько методик одновременно, а отдельный тест часто объединяет их. С учетом этого вот наиболее распространенные инструменты и их назначение.
Инструменты для тестирования компонентов
Несколько инструментов играют роль в тестировании компонентов, и большинство команд используют более одного:
- Storybook: инструмент для разработки интерфейсов, в котором вы создаете компоненты в изоляции и описываете их состояния в виде историй (stories). Эти истории выполняют роль тестов компонентов: каждая из них по умолчанию является тестом рендеринга, а поверх него вы можете добавить интерактивное тестирование с помощью функции play и при необходимости подделывать зависимости. Storybook запускает тесты в реальном браузере, в той же среде, где вы разрабатываете, что делает его особенно мощным средством для визуального и интерактивного тестирования компонентов.
- Vitest: быстрый современный тестовый фреймворк, широко используемый как для тестирования компонентов (рендеринга и взаимодействия), так и для модульного тестирования. Он предоставляет утилиты для мокирования и шпионов, на которые опираются эти тесты.
- Jest: давно зарекомендовавший себя инструмент для запуска тестов на JavaScript, используемый в основном для модульного тестирования логики интерфейса. Он поддерживает тестирование рендеринга и взаимодействия, а также мокирование, но для тестирования компонентов его используют реже, чем Vitest.
- Testing Library: библиотека для поиска элементов рендеренных компонентов и взаимодействия с ними так, как это делал бы пользователь. Она обычно используется в паре с Storybook или Vitest для обеспечения интерактивного тестирования.
- Тестирование компонентов в Cypress и Playwright. Оба инструмента наиболее известны как средства сквозного (end-to-end) тестирования, и оба также предлагают режимы тестирования компонентов, которые отрисовывают компоненты в реальном браузере и выполняют над ними интерактивные тесты.
- Визуальное тестирование Chromatic: тесты компонентов проверяют поведение, но подтверждение того, что компонент выглядит правильно, все еще требует ручной проверки пикселей. Chromatic (созданный командой Storybook) автоматизирует этот процесс, создавая снимки каждой истории и фиксируя визуальные изменения по сравнению с базовой версией. Он служит дополнительным уровнем поверх уже написанных тестов рендеринга. Он работает с историями, которые вы уже написали, что делает его естественным дополнением к тестированию компонентов. Он также обеспечивает интерактивное тестирование, заменяя Storybook в CI.
Пример: тестирование компонента в Storybook
Давайте рассмотрим пример, демонстрирующий три рассмотренных выше метода. Компонент EventForm содержит поле ввода заголовка, выбор приглашенных, который загружает людей с помощью API-вызова getUsers(), и кнопку отправки. Он вызывает onSubmit с заголовком и выбранными приглашенными.
1. Тест рендеринга
Первая история призвана помочь вам проверить, как компонент рендерится в процессе его создания.
Она также служит дымовым тестом. Когда Storybook запускает эту историю как тест, он считается успешным, если компонент рендерится без выброса исключений.
2. Интерактивный тест
Далее давайте проверим поведение компонента. Функция play запускается после рендеринга истории и взаимодействует с компонентом так, как это сделал бы пользователь. В данном случае она отправляет форму без заголовка и проверяет срабатывание валидации.
Тест запускается в реальном браузере, и вы можете наблюдать за его выполнением в пользовательском интерфейсе Storybook.
3. Тест с использованием мокирования и шпионов
EventForm загружает приглашенных из getUsers(), поэтому для тестирования успешной отправки мы подделаем этот API.
Зарегистрируйте модуль как замокированный один раз в конфигурации Storybook:
Теперь каждая история получает замокированную версию getUsers. Внутри истории укажите моку, что нужно вернуть, а затем заполните форму до конца.
Мы установили аргумент onSubmit в значение fn() на первом шаге. Это превращает его в шпион, поэтому он записывает каждый вызов. Следовательно, мы можем проверить, что он был вызван правильно.
Мок переводит компонент в известное состояние. Шпион проверяет базовую логику компонента.
Тестирование компонентов против модульного тестирования
Модульные тесты и тесты компонентов тесно связаны, так как оба вида тестов выполняются в изоляции и пишутся разработчиками, но они различаются по тому, что именно они проверяют. Модульный тест проверяет наименьшую тестируемую часть кода, часто чистую функцию, без каких-либо побочных эффектов, таких как рендеринг интерфейса. Тест компонентов рендерит реальный компонент в настоящем браузере и проверяет правильность его внешнего вида и поведения.
Полезное эмпирическое правило: используйте модульные тесты для чистой логики, независимой от пользовательского интерфейса (форматирование, вычисления, преобразование данных), и тесты компонентов для всего, что отрисовывает интерфейс или реагирует на действия пользователя.
Тестирование компонентов против интеграционного тестирования
Интеграционное тестирование проверяет совместную корректную работу нескольких модулей, а не их изоляцию. В современной практике фронтенда оно обычно не выделяется в отдельную категорию со своим собственным инструментарием. Вместо этого оно растворяется в окружающих типах тестов: тестирование дерева компонентов вместе — это по сути тест компонентов (рендеринг составного компонента и проверка объединенного поведения), в то время как тестирование интеграции фронтенда с бэкенд-сервисами и API — это по сути сквозной тест.
Другими словами, вы по-прежнему занимаетесь интеграционным тестированием, просто используя тесты компонентов для взаимодействия между компонентами и сквозные тесты для полностековых сценариев.
Тестирование компонентов против сквозного тестирования
Сквозные (E2E) тесты запускают все ваше приложение, включая фронтенд, бэкенд и API, чтобы симулировать прохождение пользователем полного сценария, такого как регистрация или оформление заказа. Это тесты с наивысшей достоверностью, которые вы можете написать, поскольку они в точности воспроизводят то, с чем сталкивается пользователь.
Обратная сторона — стоимость. Сквозные тесты работают медленнее, более подвержены сбоям и требуют значительной инфраструктуры для настройки и поддержки. Один только этап настройки может занять больше времени, чем выполнение всех остальных типов тестов вместе взятых. Именно поэтому опытные команды используют их экономно, оставляя для небольшого числа критически важных пользовательских сценариев.
Эти два подхода дополняют друг друга, а не конкурируют: сквозные тесты покрывают критические пути в вашем приложении, а тесты компонентов охватывают гораздо большую область отдельных состояний пользовательского интерфейса вокруг них.
Тестирование компонентов в эпоху агентов на базе ИИ
ИИ-агенты для написания кода могут сгенерировать компонент, настроить его свойства и выдать код пользовательского интерфейса за считанные секунды. Риск заключается в том, что они изобретают уже существующие компоненты, отклоняются от устоявшихся паттернов и галлюцинируют API. Более быстрая генерация означает больший объем кода для валидации, что делает тестирование компонентов еще более важным, а не менее.
Тестирование компонентов решает эту проблему двумя способами:
- Тесты служат защитным механизмом. Когда тест компонента падает, он возвращает конкретную, детерминированную ошибку — такую как несоответствие свойств (пропсов), нарушенное взаимодействие или нарушение доступности, — которую агент может прочитать и исправить самостоятельно. Агент генерирует код, запускает тесты, считывает информацию об ошибках и повторяет цикл до тех пор, пока тесты не пройдут; человек вмешивается только тогда, когда требуется экспертная оценка, например, при неоднозначных визуальных изменениях или для проверки соответствия результата первоначальному замыслу. Поскольку тесты компонентов выполняются быстро в реальном браузере и связывают каждый сбой с конкретным компонентом, они предоставляют агентам именно ту быструю и точную обратную связь, на которую те могут опираться.
- Истории (stories) служат контекстом. Истории, которые вы пишете для тестирования компонента, также описывают в структурированном и проверенном виде, чем является компонент и как он должен использоваться. Переданная агенту, эта запись позволяет ему создавать код на основе ваших существующих компонентов, а не изобретать новые. Истории выполняют двойную функцию: они проверяют поведение и учат агентов работать в рамках вашей системы.
Именно поэтому Storybook рассматривает тестирование компонентов как основу для разработки интерфейсов с помощью ИИ: одни и те же истории одновременно служат и вашими тестами, и контекстом, от которого зависят агенты. Подробнее см. в разделах Storybook для ИИ (Storybook for AI) и Воркингфлоу фронтенда для ИИ от Chromatic (Chromatic’s Frontend Workflow for AI).
Начать работу со Storybook »
Хотите узнать больше о лучших практиках работы со Storybook? Ознакомьтесь с нашим руководством по документации дизайн-систем:
Как документировать вашу дизайн-систему: лучшие практики и инструменты
Что освещать, какие инструменты использовать и как поддерживать актуальность документации по мере развития вашей системы.
Блог StorybookВарун Вачхар (Varun Vachhar)
Часто задаваемые вопросы
Кто обычно проводит тестирование компонентов?
Тестирование компонентов обычно выполняется фронтенд-разработчиками, которые создают компоненты, в рамках их обычного рабочего процесса, а не отдельной командой обеспечения качества (QA). Поскольку тесты пишутся параллельно с кодом компонента, их, как правило, создают и поддерживают те же люди, которые пишут пользовательский интерфейс.
Как еще называется тестирование компонентов?
Тестирование компонентов иногда называют модульным тестированием, а в контексте фронтенда оно пересекается с тем, что принято называть UI-тестированием.
Зачем использовать тестирование компонентов?
Тесты компонентов обеспечивают уверенность уровня браузера почти со скоростью и стоимостью модульных тестов. Они позволяют быстро и надежно проверить множество состояний, в которых может находиться компонент, включая те состояния, которых трудно достичь при полноценном сквозном (end-to-end) тестировании, что делает их хорошо подходящими для большинства ваших UI-тестов.
Является ли тестирование компонентов тем же самым, что и модульное тестирование?
Нет. Модульные тесты проверяют изолированную логику, как правило, в симулированной среде, в то время как тесты компонентов рендерят реальный компонент в реальном браузере и проверяют его внешний вид и поведение. Они дополняют друг друга.
Заменяют ли тесты компонентов сквозные (end-to-end) тесты?
Нет. Они дополняют их. Тесты компонентов охватывают широкий спектр отдельных состояний пользовательского интерфейса; меньшее количество сквозных тестов покрывает критически важные пользовательские сценарии, охватывающие весь стек.
