Современные фреймворки JavaScript представляют собой более простой и организованный способ создания веб-приложений. Однако они также добавляют сложности, что иногда незаметно, но впечатляюще ломает вещи.

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

Сегодня я собираюсь познакомить вас с тестированием с помощью Cypress.io - современной среды тестирования, ориентированной на интерфейс. Но сначала немного истории!

Старые способы

В течение многих лет мы полагались на такие инструменты, как Selenium для сквозных (E2E) тестов в Многостраничных веб-приложениях. Они отлично поработали. Они позволяют нам писать тесты на любом языке (Ruby, Python, JavaScript и т. Д.) Через привязку к конкретному языку. Они также представили надежное сообщество для поддержки и примеров.

Затем мы перешли на Одностраничные приложения (SPA) со сложным кодом JavaScript с использованием таких фреймворков, как React, Vue.js или Angular. У них есть API, написанный на серверном языке, таком как Ruby, Python, Go или Node.js. Теперь все начало ломаться.

Selenium и аналогичные инструменты были разработаны для тестирования приложений, требующих обновления всей страницы. О поддержке SPA с выборкой данных Ajax думали позже. Это приводит ко многим проблемам с синхронизацией и ошибочными тестами. Иногда тесты заканчивались неудачей из-за медленных запросов API или задержки в сети. Исправление этих нестандартных тестов обычно требовало добавления инструкций о сне и увеличения тайм-аутов. Это сделало тестовый код более хрупким. Не говоря уже об очень медленном.

Стоит упомянуть, что Google's Puppeteer имеет внутренний доступ к событиям веб-браузера, что позволяет нам ждать таких вещей, как вызовы Ajax. Однако написание тестов с помощью Puppeteer требует больше работы по первоначальной настройке и больше усилий для написания каждого теста, чем следовало бы.

Большинство разработчиков и команд, с которыми я разговаривал, просто отказались от идеи тестирования E2E. Они используют только автоматические тесты для проверки запросов / ответов API и (редко) модульные тесты для своих интерфейсов JavaScript.

Модульное тестирование против интеграционного тестирования против E2E-тестирования

Прежде чем идти дальше, давайте взглянем на разные уровни тестирования:

  1. E2E-тестирование - автоматическое тестирование, максимально приближенное к реальному пользователю.
  2. Интеграционное тестирование - тестирование взаимодействия двух или более блоков кода. Например, проверка того, что API отвечает ожидаемым образом при его вызове. Это вызывает все уровни функциональности от HTTP-запроса до запроса к базе данных и обратно.
  3. Модульное тестирование - изолированное тестирование одной единицы кода. Получив вход, он отвечает правильным выходом.

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

Затем, если есть изменение API, вы должны написать интеграционный тест, охватывающий по крайней мере счастливый путь и один основной печальный путь (например, запись найдена и возвращена, а запись не найдена).

Наконец, если существует много логики ветвления (например, условных операторов, циклов и т. Д.), Которые могут не выполняться на первых двух уровнях тестирования, вам следует написать модульные тесты.

В этой статье мы сосредоточимся на сквозном тестировании вашего интерфейса.

Больше никаких оправданий

Сегодня у нас нет оправдания, чтобы не иметь сильного тестового покрытия. Каждая функция, поставляемая реальным пользователям, должна проходить как минимум сквозное тестирование с использованием Cypress.io. В идеале у вас также должны быть интеграционные и модульные тесты с Jest на стороне клиента и ваша внутренняя среда языкового тестирования (например, RSpec для Ruby).

Это применимо независимо от того, следите ли вы за разработкой, управляемой тестированием (TDD) Кента Бека, или за тесно связанной с ней разработкой, основанной на поведении (BDD). Используя TDD, вы сначала пишете тест, а затем код реализации. В BDD вы сначала пишете реализацию (чтобы поэкспериментировать с дизайном вашего кода), а затем тесты. Вот те тесты, которые вам нужно пройти:

  1. Сквозные тесты - высокоуровневые тесты зеленых путей (все идет правильно) и нескольких выбранных красных путей (где одна или две вещи идут не так).
  2. Тесты запросов API - отправка запроса к вашему API и ожидание конкретного результата.
  3. Модульные тесты внешнего интерфейса - модульные тесты для таких вещей, как рендеринг компонентов, помощники кода библиотеки, код перехода между состояниями и т. д.

Неудивительно, что здесь мы сосредоточимся на №1: создании сквозных тестов с использованием Cypress.io, где тесты будут действовать как настоящий пользователь. У вас должны быть абсолютно автоматизированные тесты для вашего backend API; то, как вы их напишете, будет зависеть от языка и фреймворка, который вы используете. В качестве примера мы используем Ruby on Rails для нашего API и спецификации запросов Rspec для автоматических тестов. Наконец, для тестирования клиентской части или внешнего интерфейса обратите внимание на Jest framework Facebook.

Что отличает Cypress.io от других?

Cypress.io - относительно новый фреймворк. Он преодолевает многие недостатки, обнаруженные в Selenium, Phantom.js и других до них. Он использует архитектуру, основанную на событиях, которая подключается к событиям жизненного цикла Google Chrome. Это позволяет ему ждать завершения таких вещей, как запросы Ajax, без использования механизма опроса / тайм-аута. Это позволяет проводить надежные и быстрые тесты.

Вы можете думать о Cypress.io как о Redux автоматизированного тестирования с такими функциями, как путешествие во времени, сравнение текущего и предыдущего состояния, перезагрузка кода в реальном времени и многое другое. Вы даже можете использовать все инструменты отладки, которые вы знаете и любите, с Chrome (даже устанавливая дополнительные инструменты, такие как React Dev Tools и Redux Dev Tools).

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

Короче говоря, это действительно будущее E2E-тестирования и того, каким оно должно было быть в первую очередь.

Руководство по тестированию Cypress

Хорошо, перейдем к делу.

Добавление Cypress в ваш проект

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

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

$ yarn add cypress --dev

Затем откройте Cypress.

$ yarn run cypress open

Теперь давайте создадим наш тестовый файл:

Вышеупомянутое проверяет, может ли пользователь успешно войти в систему и выйти из нашей платформы. При успешном входе в систему они видят сообщение: «С возвращением, {firstName}». При успешном выходе они видят прощальный текст.

Все функции Cypress доступны в глобальном объекте cy, который вы видите выше. Нет необходимости в async / await или асинхронной бессмысленности. Тесты выполняются пошагово, ожидая завершения предыдущего шага.

Существуют функции для извлечения элементов DOM, таких как get(), а также для поиска текста на странице с помощью contains(). Вы можете написать тесты в стиле Behavior Driven Development и сосредоточиться на высокоуровневых действиях, выполняемых пользователем, таких как вход / выход, используя стандартные функции JavaScript, чтобы скрыть детали.

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

Давайте добавим еще один тест для проверки входа в систему с профессиональным пользователем:

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

Большой! Все, что нам нужно сделать, это добавить это s, чтобы получить logins, и перезапустить наши тесты. Конечно же, все они проходят. Пора развернуть исправление и насладиться славой и похвалой наших товарищей по команде.

Для тех из вас, кто использует VS Code, вы можете настроить автозаполнение для Cypress.

Запуск Cypress

Вы можете запускать Cypress в двух режимах: полнофункциональном и безголовом. Первый позволяет вам видеть пользовательский интерфейс вашего приложения и тесты, выполняемые поэтапно. Этот режим отлично подходит для создания набора тестов и отладки. Последний отлично подходит для среды непрерывной интеграции (CI). Еще один вариант использования безголового режима: вы просто хотите убедиться, что ничего не сломали с новыми изменениями, но не заботитесь о подробных шагах.

Чтобы открыть Cypress в полнофункциональном режиме, запустите:

$ cypress open

Чтобы открыть Cypress в безголовом режиме, запустите:

$ cypress run

Безголовый режим полезен для работы на сервере непрерывной интеграции (CI), таком как CircleCI. Как только вы начнете писать тесты более регулярно в рамках своей разработки, вам следует потратить время на настройку CI-сервера, чтобы каждый коммит git запускал весь набор тестов.

Загрузка вашего сервера

Многие среды тестирования E2E автоматически запускают сервер приложений и интерфейсный сервер при запуске теста. Cypress не предлагает эту функцию по нескольким веским причинам:

  1. Независимость от фреймворка - работает с любым интерфейсом и сервером; то, как вы запускаете свое приложение, зависит от используемого языка и фреймворка.
  2. Сложный запуск / завершение работы приложения - управление дочерним процессом или потоком может быть сложной задачей. Если процесс тестирования завершается в середине теста, дочерний процесс также завершается и может оставаться в плохом состоянии. Например, если вы очистите записи базы данных или откатите транзакции после завершения теста, эти записи останутся в базе данных и вызовут проблемы при последующих запусках.
  3. Гибкость. Вы также можете написать тесты, которые запускаются периодически, чтобы проверить, что приложение все еще доступно (например, убедитесь, что вход в систему / регистрация в производственной среде все еще работает).

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

например для узла запустите:

$ npm start

Чтобы открыть Cypress в режиме без головы в другой оболочке, запустите:

$ cypress open

Сброс состояния

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

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

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

Иногда мы не можем избежать перезапуска состояния приложения и все же необходимо очистить его. Мы действительно можем использовать after хуки, предоставленные Cypress, но это не рекомендуется. Нет никакой гарантии, что какой-либо из after обработчиков будет запущен, если набор тестов завершен или возникнет какая-либо другая ошибка, которая приведет к неожиданному сбою. Перед выполнением регулярной настройки тестов лучше произвести очистку. Взгляните на приведенные ниже примеры.

Не делайте этого:

Очистка перед тестовыми запусками:

Как видите, код практически идентичен: мы просто переместили сброс корзины в блок beforeEach для выполнения прямо перед любым из наших тестовых примеров. Мы также использовали блок before, который запускается перед любым из it тестовых случаев в описании выполнения. В этом случае мы хотели убедиться, что мы вошли в систему до начала каких-либо тестов, и что нам нужно войти в систему только один раз.

Быстрые пути

Вход и выход из системы - самые распространенные функции в нашем приложении. Мы уже написали тест, чтобы проверить, может ли пользователь войти в систему и выйти из нее должным образом. Однако действительно ли нам нужно проходить всю последовательность, если мы тестируем функцию, которую могут выполнять только зарегистрированные пользователи? Если для запуска нашего кода входа требуется 1 секунда, каждый последующий тест, требующий входа в систему, будет выполняться более 1 секунды.

Оказывается, нам не нужно использовать только наш пользовательский интерфейс для тестирования. У нас есть отличный API, который отвечает за 100 мс или меньше (ура, современные серверы). Давайте воспользуемся этим с помощью запроса Cypress.

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

Теперь мы можем использовать cy.login(email, password) вход в систему в 1/10 времени, которое потребовалось бы нам при просмотре пользовательского интерфейса.

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

Заключительные мысли

Cypress.io - надежный фреймворк для тестирования. Он представляет собой огромный скачок в производительности и инновациях для тестирования, с такими функциями, как путешествие во времени, дифференциация, режим без головы / головы, синхронное выполнение кода и многое другое. Как мы видели, легко добавить в собственный проект и сразу начать им пользоваться.

Так чего же ты ждешь? Идите, кодируйте, тестируйте и получайте удовольствие!

Ссылки

  1. Примеры использования Cypress в общих сценариях
  2. Лучшие практики в Cypress
  3. Брайан Манн - я понимаю твою точку зрения, но…

Если вам понравился этот пост, пожалуйста, уделите секунду и поделитесь им в Twitter. Есть комментарии, вопросы? Откройте раздел ниже!

Первоначально опубликовано на snipcart.com.