Что следует учитывать при написании E2E-тестов #frontend@twiliosendgrid
Опубликовано: 2020-09-19В Twilio SendGrid мы пишем сквозные (E2E) тесты в конце цикла разработки новой функции или страницы, чтобы убедиться, что все части связаны между собой и правильно работают между интерфейсом и сервером с точки зрения конечного пользователя.
Мы экспериментировали с различными средами и библиотеками тестирования E2E, такими как наша собственная собственная среда Ruby Selenium, WebdriverIO и, в первую очередь, Cypress в течение более двух лет, как указано в первой и второй частях серии сообщений в блоге, документирующих нашу миграцию во все решения. Независимо от того, какой фреймворк или библиотеку мы использовали, мы задавались одними и теми же вопросами о том, для каких функций мы можем автоматизировать и написать E2E-тесты. Определив, какие функции мы можем протестировать, мы также заметили, что снова и снова применяем одну и ту же общую стратегию для написания и настройки тестов.
Этот пост в блоге не требует каких-либо предварительных знаний о написании E2E-тестов в определенной библиотеке или среде, но он поможет, если вы видели веб-приложения и задавались вопросом, как лучше всего автоматизировать работу браузера, чтобы проверить правильность работы страниц. Мы стремимся показать вам, как думать об E2E-тестах, чтобы вы могли применить эти вопросы и общую стратегию написания тестов к любой платформе, которую вы можете выбрать.
Вопросы, которые следует задать, если вы можете автоматизировать тест E2E
Когда дело доходит до написания тестов E2E, нам нужно убедиться, что потоки на страницах, которые мы тестируем в нашем приложении, соответствуют определенным критериям. Давайте рассмотрим некоторые вопросы высокого уровня, которые мы задаем себе, чтобы определить, можно ли автоматизировать тестирование E2E.
1. Можно ли сбросить пользовательские данные обратно в определенное состояние перед каждым тестом каким-нибудь надежным способом, например через API? Если нет способа надежно сбросить пользователя обратно в нужное вам состояние, его нельзя автоматизировать и ожидать, что он будет выполняться как часть блокирующих тестов перед развертыванием. Это также антипаттерн и обычно недетерминированный возврат пользователя обратно в определенное состояние через пользовательский интерфейс, потому что это медленно, а автоматизация шагов через пользовательский интерфейс уже достаточно ненадежна. Более надежно выполнять вызовы API для сброса состояния пользователя, даже не открывая страницу в браузере. Другой альтернативой, если у вас есть существующая служба, является создание новых пользователей перед каждым тестом с соответствующими данными. Пока мы сбрасываем постоянного пользователя или создаем пользователя перед каждым тестом, мы можем сосредоточиться на тех частях страницы, которые мы тестируем.
2. Есть ли у нас контроль над функцией, API или системой, которую мы собираемся тестировать? Если это сторонняя служба, на которую вы полагаетесь для выставления счетов или для любой другой функции, есть ли способ смоделировать их или заставить их работать детерминировано с определенными значениями? Вы хотите получить как можно больше контроля над тестом, чтобы уменьшить нечеткость. Вы можете создать выделенных тестовых пользователей с изолированными ресурсами или данными для каждого тестового запуска, чтобы на него не могло повлиять что-либо еще.
3. Достаточно ли постоянна сама служба или функция, чтобы работать в разумные сроки? Часто вам может потребоваться реализовать опрос или подождать, пока определенные данные будут обработаны и переданы в базу данных (например, более медленные асинхронные обновления и инициированные события электронной почты). Если эти службы часто выполняются в течение разумного и надежного промежутка времени, вы можете установить правильные тайм-ауты опроса, пока вы ожидаете появления определенных элементов DOM или обновления данных.
4. Можем ли мы выбрать элементы, с которыми нам нужно взаимодействовать на странице? Вы имеете дело с фреймами или сгенерированными элементами, которые вы не контролируете и не можете изменить? Чтобы взаимодействовать с элементами на странице, вы можете добавить более конкретные селекторы, такие как атрибуты `data-hook` или `data-testid`, а не выбирать идентификаторы или имена классов. Идентификаторы и имена классов более подвержены изменениям, поскольку они обычно связаны со стилями. Представьте, что вы пытаетесь выбрать хешированные имена классов или идентификаторы из стилизованных компонентов или модулей CSS. Для сторонних сгенерированных элементов или библиотек компонентов с открытым исходным кодом, таких как react-select, вы можете обернуть эти элементы родительским элементом с атрибутом `data-hook` и выбрать дочерние элементы под ним. Для работы с фреймами мы создали пользовательские команды для извлечения элементов DOM, которые нам нужно утвердить и с которыми нужно действовать, пример которых мы приведем позже.
Есть и другие соображения, которые необходимо учитывать, но все они сводятся к одному вопросу: можем ли мы последовательно и своевременно повторять этот E2E-тест и достигать тех же результатов?
Общая стратегия написания E2E-тестов
1. Определите важные тестовые случаи, которые мы можем автоматизировать . Некоторые примеры включают тесты счастливого пути, охватывающие большую часть потока функций: выполнение операций CRUD через пользовательский интерфейс для информации профиля пользователя, фильтрация таблицы для сопоставления результатов с некоторыми данными, создание публикации или настройка ключа API. Однако другие пограничные случаи и обработку ошибок лучше покрыть модульными и интеграционными тестами. Запустите его через вопросы, которые мы упоминали в предыдущем разделе, чтобы сократить список тестовых случаев.
2. Подумайте, как повторить эти тесты, максимально настроив или разобрав API. Для высокоэффективных автоматических тестовых случаев начните замечать, какие вещи вы должны настроить через API. Некоторые примеры заполняют пользователя правильными данными, если у пользователя недостаточно фильтруемых данных для разбивки на страницы, если срок действия данных пользователя истекает в скользящем окне в 30 дней или если нам нужно, возможно, удалить некоторые данные, оставшиеся после успешного или неполного завершения. тесты, прежде чем текущий тест начнется снова. Тесты должны иметь возможность запускаться и устанавливать себя в одном и том же повторяемом состоянии независимо от того, насколько успешным или неудачным был последний запуск теста.
Важно подумать: как я могу сбросить данные этого пользователя обратно к исходной точке, чтобы я мог протестировать только ту часть функции, которую хочу?
Например, если вы хотите проверить способность пользователя добавлять сообщение, чтобы оно в конечном итоге отображалось в списке сообщений пользователя, сообщение должно быть сначала удалено.
3. Встаньте на место вашего клиента и отслеживайте шаги пользовательского интерфейса, необходимые для полного завершения потока функций. Запишите шаги, необходимые клиенту для завершения полного потока или действия. Следите за тем, что пользователь должен или не должен видеть или с чем взаимодействовать после каждого шага. По ходу дела мы будем проводить проверки работоспособности и утверждения, чтобы убедиться, что пользователи сталкиваются с правильной последовательностью событий для своих действий. Затем мы переведем проверки работоспособности в автоматизированные команды и утверждения.
4. Сохраняйте изменения и автоматизируйте потоки, добавляя определенные селекторы и реализуя объекты страницы (или любую другую оболочку). Просмотрите те шаги, которые вы записали, чтобы понять, как маневрировать и проходить поток функций. Добавьте более конкретные селекторы, такие как атрибуты data-hook, к элементам, с которыми взаимодействовал пользователь, таким как кнопки, модальные окна, поля ввода, строки таблицы, оповещения и карточки. При желании вы можете создавать объекты страницы, оболочки или вспомогательные файлы со ссылками на эти элементы с помощью добавленных вами селекторов. Затем вы можете реализовать повторно используемые функции для взаимодействия с активными элементами страницы.
5. Переведите записанные вами шаги пользователя в тесты Cypress с помощью созданных вами хелперов. В тестах мы обычно входим в систему пользователя через API и сохраняем файл cookie сеанса перед запуском каждого тестового случая, чтобы оставаться в системе. Затем мы настраиваем или удаляем данные пользователя через API, чтобы иметь согласованную отправную точку. Когда все готово, мы заходим на страницу, которую будем тестировать непосредственно для нашей функции. Мы приступаем к выполнению шагов для потока, таких как создание, обновление или удаление потока, утверждая, что должно произойти или быть видимым на странице по пути. Чтобы ускорить тесты и уменьшить нестабильность, избегайте сброса или создания состояния через пользовательский интерфейс и обходите такие вещи, как вход в систему через страницу входа или удаление элементов через пользовательский интерфейс, чтобы сосредоточиться на частях, которые вы хотите протестировать. Обязательно всегда выполняйте эти части в хуках `before` или `beforeEach`. В противном случае, если вы использовали хуки `after` или `afterEach`, тесты могут завершиться ошибкой между ними, что приведет к тому, что ваши шаги очистки никогда не будут выполняться, а последующие запуски тестов будут терпеть неудачу.
6. Забить и отштамповать тест на лещадность. После реализации тестов, которые пару раз проходят локально, возникает соблазн настроить запрос на вытягивание, сразу же объединить его и запустить тесты по расписанию с остальной частью вашего набора тестов или запустить их на этапах развертывания. Прежде чем сделать это:
- Во-первых, попробуйте оставить пользователя в различных состояниях и посмотреть, проходят ли ваши тесты, чтобы убедиться, что у вас есть правильные шаги настройки.
- Затем исследуйте параллельный запуск тестов, когда они запускаются во время одного из ваших потоков развертывания. Это позволяет вам видеть, используются ли ресурсы одними и теми же пользователями и возникают ли какие-либо условия гонки.
- Затем посмотрите, как ваши тесты выполняются в автономном режиме в контейнере Docker, чтобы увидеть, не нужно ли вам увеличить время ожидания или настроить какие-либо селекторы.
Цель состоит в том, чтобы увидеть, как ваши тесты ведут себя при повторных запусках тестов в разных условиях, и сделать их максимально стабильными и последовательными, чтобы мы тратили меньше времени на исправление тестов и больше фокусировались на обнаружении реальных ошибок в наших средах.
Вот пример макета тестового шаблона Cypress, в котором мы создали команду глобальной поддержки входа в систему под названием «cy.login (имя пользователя, пароль)». Мы явно устанавливаем файл cookie и сохраняем его перед каждым тестом, чтобы мы могли оставаться в системе и идти напрямую на страницы, которые мы тестируем. Мы также выполняем некоторую настройку или демонтаж через API и каждый раз обходим страницу входа, как показано ниже.
Конечные мысли
Помимо сравнения того, какое решение E2E лучше всего использовать, важно также принять правильное мышление для тестирования E2E. Крайне важно сначала задать вопросы о том, соответствует ли функция, которую вы хотите протестировать, требованиям для автоматизации. У вас должны быть способы надежно сбросить пользователя или данные обратно в определенное состояние (например, через API), чтобы вы могли сосредоточиться на том, что вы пытаетесь проверить.
Если нет надежного способа сбросить вашего пользователя или данные до надлежащей отправной точки, вам следует изучить инструменты и API-интерфейсы для создания пользователей с определенными конфигурациями. Вы также можете смоделировать то, что вы можете контролировать, чтобы сделать тесты максимально стабильными и последовательными. В противном случае вы должны рассмотреть ценность и компромиссы со своей командой. Следует ли оставить эту функцию для модульных тестов или ручного регрессионного тестирования, когда вносятся новые изменения кода?
Для тех функций, которые вы можете автоматизировать в тестах E2E, часто наиболее ценно охватить основные потоки счастливого пути ваших пользователей. Еще раз, делайте вещи повторяемыми своевременным и последовательным образом и устраняйте ненадежность, когда вы пишете E2E-тесты с любым фреймворком или библиотекой, которые вы хотите.
Для получения дополнительной информации о конкретных тестах Cypress E2E ознакомьтесь со следующими ресурсами:
- 1000-футовый обзор написания тестов Cypress
- TypeScript — все, что нужно для ваших тестов Cypress
- Работа с потоками электронной почты в тестах Cypress
- Идеи по настройке, организации и объединению ваших тестов Cypress
- Интеграция тестов Cypress с Docker, Buildkite и CICD