Уверенное тестирование приложений JavaScript

Бесспорно, за последние несколько лет в мире JavaScript многое изменилось. Это не должно вызывать удивления. Мы особенно рады видеть большой прогресс в том, как мы пишем и думаем о тестировании в экосистеме JavaScript.

Если сделать небольшой шаг назад, то года 3–4 назад ситуация уже была многообещающей. Средства запуска тестов, такие как Jest, уже были довольно популярны, обеспечивая хороший опыт разработчика, а тестирование компонентов React в значительной степени продиктовано Enzyme.

Мы в commercetools были в восторге от инструментов, которые были в нашем распоряжении, и мы попытались внедрить в нашей команде некоторые передовые методы написания хороших модульных тестов. Об этом мы писали в этой статье: Тестирование в React: лучшие практики, советы и хитрости.

Однако, если бы я перечитал это сейчас, моей реакцией было бы неодобрение большей части того, о чем говорится в статье. Да, действительно, поскольку это просто показывает, как многое изменилось с тех пор.

К счастью, они изменились к лучшему! Давайте посмотрим, что именно изменилось.

Тестирование менталитета

Ранее мы упоминали, что в нашем распоряжении есть хорошие инструменты для тестирования. Чего, по нашему мнению, не хватало, так это фундаментального мышления о том, как мы должны подходить к написанию и размышлениям о тестировании.

Благодаря усилиям сообщества и наставлениям Кента К. Доддса способ тестирования приложений JavaScript радикально изменился.

Чем больше ваши тесты похожи на то, как используется ваше программное обеспечение, тем больше уверенности они могут вам дать.

Ключевой вывод из этого - то, как мы думаем о том, что нужно тестировать. Традиционно большинство из нас (мы предполагаем) писали тесты, которые также тестировали большую часть внутренних компонентов, например, компонентов пользовательского интерфейса, что приводило к разочарованию и проблемам при необходимости рефакторинга кода, поскольку приходилось изменять как реализацию, так и тесты. В конце концов, одна из основных причин написания тестов - это возможность уверенно перейти к реализации в будущем.

В результате тесты должны быть связаны только с тем, что конечный пользователь видит и с чем может взаимодействовать. Следовательно, тесты не зависят от деталей реализации, что позволяет проводить гораздо более уверенный рефакторинг, поскольку нужно изменять только реализацию, а не конечный результат и, следовательно, тесты.

Чтобы следовать этому менталитету и применять передовые методы, DOM Testing Library & Co. были рождены.

Если вы хотите узнать больше по этим темам, ознакомьтесь со следующими ресурсами:

Для нас в commercetools это очень помогло переосмыслить и переоценить то, как мы хотим писать тесты. Что наиболее важно, мы увидели следующие преимущества:

  • У нас гораздо больше уверенности при рефакторинге существующего кода или внедрении новых функций, поскольку мы можем полагаться на стабильные тесты.
  • Мы не пишем тесты для каждого компонента, а пишем больше на уровне приложения, что дает нам более глубокий охват того, что тестируется. Это неявно помогает нам также тестировать такие вещи, как маршрутизация.
  • Библиотека тестирования DOM способствует написанию и тестированию доступных компонентов.

Получение данных и имитация

В Jest уже есть хорошая система издевательств. Однако он оставляет много места для тестирования загрузки данных в компонентах.

Мы в commercetools в основном используем GraphQL и Apollo, особенно в наших интерфейсных приложениях.
В Apollo есть компонент Mocked Provider, который можно использовать для имитации запросов GraphQL. Это чрезвычайно полезно при тестировании на уровне приложения и, в свою очередь, очень хорошо сочетается с подходом библиотеки тестирования DOM.

Тем не менее, имитация запросов GraphQL с помощью Apollo Mocked Provider показала свои недостатки. Одна из причин заключается в том, что совпадающие запросы могут быть довольно подробными, и разные сценарии может быть трудно различить, например, с частичными данными или разными кодами состояния HTTP. Частично это связано с тем, что имитировать невозможно достаточно близко к сетевому уровню, поскольку он полагается на сам Apollo.

Мы также можем утверждать, что использование моков Apollo требует знания деталей реализации запросов, что в идеале не является тем, к чему мы должны стремиться (как упоминалось ранее).

Следовательно, лучшим вариантом было бы издевательство непосредственно на сетевом уровне и, таким образом, устранение необходимости для Apollo диктовать поведение насмешки. Используя библиотеки, такие как xhr-mock, мы можем перехватывать запросы и обрабатывать их в соответствии с предопределенными правилами сопоставления. Например, для запросов GraphQL мы можем сопоставить запросы GraphQL по имени их операции. Apollo также предлагает инструменты для автоматического создания фиктивных данных на основе схемы GraphQL.

Этот подход больше соответствует менталитету тестирования того, как приложение ведет себя, а не того, как оно реализовано.

Имитация сервис-воркера

К счастью, чтобы упростить имитацию запросов на сетевом уровне, есть новая библиотека под названием Mock Service Worker (MSW).

Предоставляя возможность Service Workers захватывать запросы с целью кэширования, Mock Service Worker позволяет имитировать API на самом высоком уровне сетевой коммуникационной цепочки. Это самый близкий к имитирующему серверу без необходимости его создания.

Мы в commercetools искали и опробовали эту библиотеку в последние месяцы, и до сих пор мы были очень довольны ею.
Мы обнаружили, что тестовая установка для имитации сетевых запросов намного проще, для Например, используя насмешки Apollo. Он также работает как для запросов GraphQL, так и для запросов REST, поэтому для обоих можно использовать один и тот же метод имитации. Наконец, MSW можно использовать как в браузере, так и в среде Node.js, избавляя от необходимости знать и использовать разные библиотеки.

Переход на использование MSW также прошел довольно легко, поскольку все, что нам нужно было сделать, это заменить установку имитации запросов, и тесты продолжали работать, как и раньше.

Кроме того, помимо некоторых приятных функций MSW, основная идея MSW следует тем же принципам тестирования, которые мы обсуждали ранее: проверьте, как приложение ведет себя, а не как оно построено.

Вместо того, чтобы утверждать, что запрос был сделан или имел верные данные, проверьте, как ваше приложение отреагировало на этот запрос.

Однако мы по-прежнему можем выполнять проверки входящих запросов, отправляя ответ с ошибкой.

Мы можем только порекомендовать его проверить и попробовать.

Данные испытаний

Другой важный аспект тестирования - это базовые тестовые данные. Часто вы в конечном итоге записываете одни и те же «поддельные» данные в кучу тестов, возможно, также опуская определенные поля, потому что они не используются в этом конкретном сценарии тестирования. Кроме того, данные могут даже не охватывать сценарии реального мира, что делает большинство тестов практически бессмысленными.

Этот процесс очень подробный и подвержен ошибкам, и мы в commercetools сталкиваемся с этими проблемами все чаще и чаще в последние годы. С увеличением количества API-интерфейсов на нашей платформе необходимость поддерживать тесты таким образом вообще не масштабируется.

Поэтому мы решили заняться этой проблемой и начали инициативу по созданию сгенерированных тестовых данных.
Короче говоря, идея состоит в том, что каждая сущность в API нашей платформы определяется как модель тестовых данных. Модель содержит все доступные поля для этой сущности, большинство из которых генерируются как случайные значения с использованием библиотеки faker.
У нас также есть концепция, называемая преобразователем, где мы можем получить другое представление базовой модели, например для форма, подобная GraphQL или REST.

Объединение этого с инструментами тестирования, такими как DOM Testing Library и MSW, дает очень мощную комбинацию, которая упрощает настройку тестов, позволяя нам больше сосредоточиться на том, что имеет значение: на написании надежных тестов с уверенностью.

Заключение

Подход, который вы применяете к тестированию приложения, имеет решающее значение, и, что наиболее важно, тесты должны помочь вам и вашей команде обрести нужный уровень уверенности, а не мешать.

В commercetools мы очень довольны тем, как мы постоянно стремимся улучшить наш подход к тестированию, поскольку он много раз доказывал свою полезность и помогал нам быть более продуктивными и, конечно, более уверенными. Наличие хорошего уровня уверенности - это то, что также позволяет нам делать такие вещи, как непрерывное развертывание (поезд развертывания).

Если большая часть этого звучит для вас в новинку, мы действительно рекомендуем вам начать переосмысливать подход к тестированию приложения и компонентов пользовательского интерфейса и выбрать инструменты, которые помогут вам писать устойчивые и содержательные тесты.
Что еще более важно, вы не должны Не надо сразу все переписывать. Например, мы рекомендуем переписать тесты с нуля на основе существующих тестовых сценариев и удалить все предыдущие тесты, связанные с этой функциональностью, вместо того, чтобы пытаться переписать предыдущие тесты.

Например, у нас все еще есть части нашей кодовой базы, в которых используется «устаревший подход к тестированию», и это время от времени вызывает проблемы. Когда у нас есть возможность, мы пишем тесты для этой части функциональности как новые тесты и удаляем предыдущие тестовые файлы.

Удачного тестирования!