Тестирование конвейера 101 для тестирования внешнего интерфейса

Опубликовано: 2022-03-10
Краткое резюме ↬ Автоматическое тестирование может дать вам большую уверенность при объединении ваших изменений, особенно при обширном рефакторинге или работе с вашими товарищами по команде. В результате вы, возможно, подумали о включении тестирования в процедуру сборки, чтобы получить от нее максимальную отдачу. Не знаете с чего начать? Давайте вместе реализуем ваш конвейер тестирования с нуля.

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

В известном сериале действительно есть похожая сцена: это из третьего сезона телесериала Netflix «Как продавать наркотики онлайн (быстро)»:

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

Поехали!

Перво-наперво: основные термины

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

Если вы погуглите в мире тестирования в целом, может случиться так, что вы уже наткнулись на термины «CI/CD» в качестве одного из первых терминов. Это сокращение от «Continuous Integration, Continuous Delivery» и «Continuous Deployment» и описывает именно это: как вы, вероятно, уже слышали, это метод распространения программного обеспечения, используемый группами разработчиков для более частого и надежного развертывания изменений кода. CI/CD включает в себя два взаимодополняющих подхода, которые в значительной степени зависят от автоматизации.

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

CD — это аббревиатура от «Continuous Delivery» и «Continuous Deployment», обе концепции похожи друг на друга, но иногда используются в разных контекстах. Разница между ними заключается в области автоматизации:

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

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

Для достижения хорошо продуманной стратегии CI/CD большинство людей и организаций используют процессы, называемые «конвейерами». «Конвейер» — это слово, которое мы уже использовали в этом руководстве, не объясняя его. Если вы думаете о таких трубопроводах, не будет слишком надуманным думать о трубах, служащих междугородними линиями для транспортировки таких вещей, как газ. Конвейер в области DevOps работает аналогично: он «транспортирует» программное обеспечение для развертывания.

Иллюстрация пайплайна в виде трубы с тремя секциями: сборка, тестирование, развертывание
«Настоящий» конвейер CI/CD включает в себя несколько шагов, которые необходимо выполнить для развертывания новой версии программного обеспечения и, как следствие, автоматизации процесса доставки программного обеспечения. (Большой превью)

Подождите, звучит так, будто нужно многому научиться и запомнить, верно? Разве мы не говорили о тестировании? В этом вы правы: полная концепция конвейера CI/CD предоставит достаточно контента для нескольких статей, и мы хотим позаботиться о конвейере тестирования для небольших интерфейсных проектов. Или вы упускаете только аспект тестирования своих пайплайнов, таким образом, фокусируясь только на процессах непрерывной интеграции. Итак, в частности, мы сосредоточимся на части «Тестирование» пайплайнов. Поэтому в этом руководстве мы создадим «небольшой» конвейер тестирования.

Итак, «тестовая часть» — наша основная задача. В связи с этим, какие тесты вы уже знаете и что приходит вам на ум с первого взгляда? Если я думаю о тестировании таким образом, я спонтанно думаю о следующих типах тестирования:

  • Модульное тестирование — это тип теста, в котором второстепенные тестируемые части или модули приложения, называемые модулями, индивидуально и независимо проверяются на правильность работы.
  • Интеграционное тестирование фокусируется на взаимодействии между компонентами или системами. Этот тип тестирования означает, что мы проверяем взаимодействие модулей и то, как они работают вместе.
  • End-To-End Testing , или E2E-тестирование, означает, что фактические действия пользователя имитируются компьютером; при этом E2E-тестирование должно включать как можно больше функциональных областей и частей технологического стека, используемых в приложении.
  • Визуальное тестирование — это процесс проверки видимого вывода приложения и сравнения его с ожидаемыми результатами. Иными словами, это помогает найти «визуальные ошибки» во внешнем виде страницы или экрана, отличные от чисто функциональных ошибок.
  • Статический анализ — это не совсем тестирование, но я думаю, что здесь необходимо упомянуть об этом. Вы можете представить, что он работает как исправление орфографии: он отлаживает ваш код без запуска программы и обнаруживает проблемы со стилем кода. Эта простая мера может предотвратить многие ошибки.

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

Еще после прыжка! Продолжить чтение ниже ↓

Стратегия: пирамиды и трофеи

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

Первая метафора, с которой вы, вероятно, столкнетесь, — это пирамида автоматизации тестирования. Майк Кон предложил эту концепцию в своей книге «Успех с помощью Agile», получившей дальнейшее развитие Мартина Фаулера как «Пирамида практических испытаний». Это выглядит так:

Тестовая пирамида
«Пирамида практических испытаний» Мартина Фаулера (большой превью)

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

  1. Единица измерения
    Вы найдете эти тесты на базовом уровне пирамиды, потому что они быстро выполняются и просты в обслуживании. Это связано с их изоляцией и тем фактом, что они нацелены на самые маленькие единицы. См. этот пример типичного модульного теста для тестирования очень маленького продукта.
  2. Интеграция
    Они находятся в середине пирамиды, поскольку они по-прежнему приемлемы, когда речь идет о скорости выполнения, но при этом дают вам уверенность в том, что вы находитесь ближе к пользователю, чем могут быть модульные тесты. Примером теста интеграционного типа является API-тест, также к этому типу можно отнести компонентные тесты.
  3. Тесты E2E (также называемые тестами пользовательского интерфейса )
    Как мы видели, эти тесты имитируют реального пользователя и его взаимодействие. Эти тесты требуют больше времени для выполнения и, следовательно, являются более дорогими — они находятся на вершине пирамиды. Если вы хотите изучить типичный пример для теста E2E, перейдите к этому.

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

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

«Напишите тесты. Не так много. В основном интеграция».

— Гильермо Раух

Давайте разберем эту цитату, чтобы узнать об этом:

  • Пишите тесты
    Совершенно очевидно — вы всегда должны писать тесты. Тесты имеют решающее значение для создания доверия внутри вашего приложения — как для пользователей, так и для разработчиков. Даже для себя!
  • Не так много
    Написание тестов наугад ни к чему не приведет; пирамида тестирования по-прежнему действительна в своем утверждении, чтобы поддерживать приоритетность тестов.
  • В основном интеграция
    Козырная карта более «дорогих» тестов, которые пирамида игнорирует, заключается в том, что доверие к тестам возрастает по мере продвижения вверх по пирамиде. Это увеличение означает, что и пользователь, и вы как разработчик, скорее всего, будете доверять этим тестам.

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

Если вы следуете за Кентом К. Доддсом, эти рассуждения могут показаться вам знакомыми, особенно если вы читали именно эту статью, написанную им. Эти аргументы не случайны: он придумал новую стратегию в своей работе. Я полностью согласен с его точками зрения и ставлю ссылку на самую важную здесь, а другие — в разделе ресурсов. Предлагаемый им подход исходит из пирамиды тестирования, но поднимает ее на другой уровень, изменяя ее форму, чтобы отразить более высокий приоритет интеграционных тестов. Он называется «Тестовый трофей».

Трофей за испытания
Я сделал быстрый набросок, который может быть неточным в масштабе, но донесет свою мысль. (Большой превью)

Награда за тестирование — это метафора, изображающая гранулярность тестов немного по-другому; вам следует распределить свои тесты по следующим типам тестирования:

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

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

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

Как построить эти конвейеры онлайн (быстро)

Главный герой третьего сезона телесериала Netflix «Как продавать наркотики в Интернете (быстро)» показан с использованием Cypress для E2E-тестирования, когда срок приближается к крайнему сроку, однако на самом деле это было только локальное тестирование. Никакого CI/CD не было видно, что вызывало у него ненужный стресс. Мы должны избегать давления данного главного героя в соответствующих эпизодах с теорией, которую мы изучили. Однако как мы можем применить эти знания в реальности?

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

Мое предложение основного трубопровода

Первое, что пришло мне в голову, было самоочевидным: мой веб-сайт, т. е. страница моего портфолио, вполне подходит для того, чтобы его можно было рассматривать в качестве примера кодовой базы для тестирования нашим амбициозным пайплайном. Он опубликован с открытым исходным кодом на Github, так что вы можете свободно просматривать и использовать его. Несколько слов о техническом стеке сайта: в основном, я построил этот сайт на Vue.js (к сожалению, все еще на версии 2, когда я писал эту статью) в качестве JavaScript-фреймворка с Nuxt.js в качестве дополнительного веб-фреймворка. Вы можете найти полный пример реализации в репозитории GitHub.

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

Авторское предложение основного трубопровода
Вы заметили, что одна из скобок на моем изображении конвейера имеет прозрачный цвет? Я раскрашивал специально; это тот момент, откуда исходит мой небольшой отказ от ответственности. (Большой превью)

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

  • Определение модуля часто «обсуждается»: если вы попросите группу разработчиков определить модуль, вы в основном получите разные, отличающиеся друг от друга ответы. Поскольку некоторые относятся к функции, классу или сервису — второстепенным единицам — другой разработчик будет учитывать полный компонент.
  • В дополнение к этим проблемам с определением, провести границу между единицей и интеграцией может быть сложно, так как она очень размыта. Эта борьба реальна, особенно для Frontend, поскольку нам часто требуется DOM для успешной проверки тестовой основы.
  • Обычно можно использовать одни и те же инструменты и библиотеки для написания обоих интеграционных тестов. Таким образом, мы могли бы сэкономить ресурсы, объединив их.

Инструмент выбора: Действия GitHub

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

  • GitLab, судя по распорядку дня на моем рабочем месте,
  • GitHub Actions в большинстве моих побочных проектов.

Тем не менее, есть много других платформ на выбор. Я бы посоветовал всегда основывать свой выбор на ваших проектах и ​​их конкретных требованиях, учитывая используемые технологии и фреймворки — чтобы не возникало проблем с совместимостью. Помните, мы используем проект Vue 2, который уже был выпущен на GitHub, что по совпадению совпадает с моим предыдущим опытом. Кроме того, для упомянутых действий GitHub в качестве отправной точки требуется только репозиторий GitHub вашего проекта; для создания и запуска рабочего процесса GitHub Actions специально для него. Как следствие, я выберу GitHub Actions для этого руководства.

Таким образом, эти действия GitHub предоставляют вам платформу для запуска специально определенных рабочих процессов, если происходят определенные события. Эти события представляют собой определенные действия в нашем репозитории, запускающие рабочий процесс, например, отправка изменений в ветку. В этом руководстве эти события привязаны к CI/CD, но такие рабочие процессы могут также автоматизировать другие рабочие процессы, такие как добавление меток к запросам на вытягивание. GitHub может выполнять их на виртуальных машинах Windows, Linux и macOS.

Чтобы визуализировать такой рабочий процесс, он будет выглядеть так:

Иллюстрация рабочего процесса GitHub Action.
Рабочий процесс Github Action — это настраиваемый автоматизированный процесс (поэтому весь процесс показан зеленым цветом). (Большой превью)

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

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

  1. Шаг может запускать простой скрипт.
  2. Шаг может запускать действие. Такое действие является многоразовым расширением и часто представляет собой законченное пользовательское приложение.

Имея это в виду, фактический рабочий процесс действия GitHub выглядит следующим образом:

Рабочий процесс действия GitHub с некоторыми пояснениями автора
Первый взгляд на синтаксис — все в одном. (Большой превью)

Пишем наш самый первый экшен на GitHub

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

Поэтому я сначала создаю .github/workflows/ для хранения наших рабочих процессов. Мы создадим новый файл с tests.yml , чтобы содержать наш рабочий процесс тестирования внутри этого каталога. Наряду со стандартным синтаксисом рабочего процесса, показанным на рисунке выше, я буду действовать следующим образом:

  1. Я назову наш рабочий процесс Tests CI .
  2. Поскольку я хочу выполнять свой рабочий процесс при каждой отправке в мои удаленные ветки и предоставлять возможность запуска конвейера вручную, я настрою свой рабочий процесс для запуска при push и workflow_dispatch .
  3. И последнее, но не менее важное: как указано в параграфе «Мое предложение по базовому конвейеру», мой рабочий процесс будет состоять из трех заданий:
    • static-eslint для статического анализа;
    • unit-integration-jest для объединения модульного и интеграционного тестирования в одну работу;
    • ui-cypress как этап пользовательского интерфейса, включая базовый тест E2E и визуальное регрессионное тестирование.
  4. Виртуальная машина на базе Linux должна выполнять все задания, поэтому я ubuntu-latest .

Вставьте правильный синтаксис файла YAML , первая схема нашего рабочего процесса может выглядеть так:

 name: Tests CI on: [push, workflow_dispatch] # On push and manual jobs: static-eslint: runs-on: ubuntu-latest steps: # 1 steps unit-integration-jest: runs-on: ubuntu-latest steps: # 1 step ui-cypress: runs-on: ubuntu-latest steps: # 2 steps: e2e and visual

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

Статический анализ

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

  • Eslint как средство исправления стиля кода Javascript.
  • Stylelint для исправления кода CSS.
  • Мы можем пойти еще дальше, например, для анализа сложности кода вы можете воспользоваться такими инструментами, как анализатор.

Общее у этих инструментов то, что они указывают на ошибки в шаблонах и соглашениях. Однако имейте в виду, что некоторые из этих правил — дело вкуса. Вам решать, насколько строго вы хотите их применять. Чтобы назвать пример, если вы собираетесь терпеть отступ в две или четыре вкладки. Гораздо важнее сосредоточиться на требованиях к согласованному стилю кода и выявлении более важных причин ошибок, таких как использование «==» вместо «===».

Для нашего портфолио проекта и этого руководства я хочу начать установку Eslint, так как мы используем много Javascript. Я установлю его с помощью следующей команды:

 npm install eslint --save-dev

Конечно, я также могу использовать альтернативную команду с менеджером пакетов Yarn, если я предпочитаю не использовать NPM. После установки мне нужно создать файл конфигурации с именем .eslintrc.json . Давайте пока воспользуемся базовой конфигурацией, так как эта статья не научит вас, как настроить Eslint в первую очередь:

 { "extends": [ "eslint:recommended", ] }

Если вы хотите подробно узнать о настройке Eslint, перейдите к этому руководству. Далее мы хотим сделать наши первые шаги по автоматизации выполнения Eslint. Для начала я хочу настроить команду на выполнение Eslint как NPM-скрипта. Я достигаю этого, используя эту команду в нашем файле package.json в разделе script :

 "scripts": { "lint": "eslint --ext .js .", },

Затем я могу выполнить этот вновь созданный скрипт в нашем рабочем процессе GitHub. Однако перед этим нам нужно убедиться, что наш проект доступен. Поэтому мы используем предварительно сконфигурированное действие GitHub Actions actions/checkout@v2 , которое делает именно это: проверяет наш проект, чтобы рабочий процесс вашего действия GitHub мог получить к нему доступ. Следующим шагом будет установка всех зависимостей NPM, которые нам нужны для моего портфолио проекта. После этого мы, наконец, готовы запустить наш скрипт eslint! Наша последняя работа по использованию линтинга теперь выглядит так:

 static-eslint: runs-on: ubuntu-latest steps: # Action to check out my codebase - uses: actions/checkout@v2 # install NPM dependencies - run: npm install # Run lint script - run: npm run lint

Теперь вы можете задаться вопросом: этот конвейер автоматически «отказывается», когда наш npm run lint при неудачном тесте? Да, это работает из коробки. Как только мы закончим писать наш рабочий процесс, мы посмотрим на скриншоты на Github.

Блок и интеграция

Затем я хочу создать наше задание, содержащее этапы модуля и интеграции. Что касается фреймворка, используемого в этой статье, я хотел бы познакомить вас с фреймворком Jest для фронтенд-тестирования. Конечно, вам не нужно использовать Jest, если вы этого не хотите — есть много альтернатив на выбор:

  • Cypress также предлагает тестирование компонентов, которое хорошо подходит для интеграционных тестов.
  • Jasmine — еще один фреймворк, на который стоит обратить внимание.
  • И многое другое; Я просто хотел назвать несколько.

Jest предоставляется Facebook с открытым исходным кодом. Фреймворк делает упор на простоту и совместимость со многими фреймворками и проектами JavaScript, включая Vue.js, React или Angular. Я также могу использовать шутку в тандеме с TypeScript. Это делает фреймворк очень интересным, особенно для моего небольшого портфолио, поскольку он совместим и хорошо подходит.

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

 npm install --save-dev jest

После установки я уже могу начать писать тесты. Однако в этой статье основное внимание уделяется автоматизации этих тестов с помощью действий Github. Итак, чтобы узнать, как написать модульный или интеграционный тест, обратитесь к следующему руководству. При настройке задания в нашем рабочем процессе мы можем действовать аналогично static-eslint . Итак, первый шаг — снова создать небольшой скрипт NPM для дальнейшего использования в нашей работе:

 "scripts": { "test": "jest", },

После этого мы определим задание под названием unit-integration-jest аналогично тому, что мы уже делали для наших линтеров ранее. Итак, рабочий процесс проверит наш проект. В дополнение к этому мы будем использовать два небольших отличия от нашего первого задания static-eslint :

  1. Мы будем использовать действие как шаг для установки Node.
  2. После этого мы будем использовать наш недавно созданный скрипт npm для запуска нашего теста Jest.

Таким образом, наша работа unit-integration-jest будет выглядеть так:

 unit-integration-jest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 # Set up node - name: Run jest uses: actions/setup-node@v1 with: node-version: '12' - run: npm install # Run jest script - run: npm test

UI-тесты: E2E и визуальное тестирование

И последнее, но не менее важное: мы напишем наше ui-cypress , которое будет содержать как E2E-тестирование, так и визуальное тестирование. Умно сочетать эти две задачи в одной работе, так как я буду использовать платформу Cypress для обеих задач. Конечно, вы можете рассмотреть и другие фреймворки, такие как NightwatchJS и CodeceptJS.

Опять же, мы рассмотрим только основы, чтобы настроить его в нашем рабочем процессе GitHub. Если вы хотите подробно узнать, как писать тесты Cypress, я познакомил вас с другим моим руководством, посвященным именно этому. Эта статья проведет вас через все, что нам нужно, чтобы определить этапы тестирования E2E. Хорошо, сначала мы установим Cypress так же, как мы это делали с другими фреймворками, используя следующую команду в нашей корневой папке:

 npm install --save-dev cypress

На этот раз нам не нужно определять скрипт NPM. Cypress уже предоставляет нам собственное действие GitHub, cypress-io/github-action@v2 . Там нам нужно только настроить некоторые вещи, чтобы он заработал:

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

К счастью, наше действие Cypress помогает нам хранить все эти конфигурации в области with . Таким образом, наша текущая работа GitHub выглядит так:

 steps: - name: Checkout uses: actions/checkout@v2 # Install NPM dependencies, cache them correctly # and run all Cypress tests - name: Cypress Run uses: cypress-io/github-action@v2 with: browser: chrome headless: true # Setup: Nuxt-specific things build: npm run generate start: npm run start wait-on: 'http://localhost:3000'

Визуальные тесты: обратите внимание на свой тест

Помните наше первоначальное намерение написать это руководство: у меня есть значительный рефакторинг с большим количеством изменений в файлах SCSS — я хочу добавить тестирование как часть процедуры сборки, чтобы убедиться, что это не сломает ничего другого. Имея статический анализ, модульные, интеграционные и E2E-тесты, мы должны быть достаточно уверены, верно? Верно, но я все еще могу кое-что сделать, чтобы мой пайплайн был еще более надежным и совершенным. Можно сказать, что он становится сливочником. Особенно при работе с рефакторингом CSS E2E-тест может оказать лишь ограниченную помощь, поскольку он делает только то, что вы сказали, записывая это в своем тесте.

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

Существует множество инструментов визуального тестирования, на которые стоит обратить внимание:

  • Percy.io, инструмент от Browserstack, который я использую для этого руководства;
  • Visual Regression Tracker, если вы предпочитаете не использовать SaaS-решение и в то же время использовать полностью открытый исходный код;
  • Applitools с поддержкой ИИ. В журнале Smashing есть интересное руководство по этому инструменту;
  • Хроматический сборник рассказов.

Для этого руководства и в основном для моего проекта портфолио было жизненно важно повторно использовать мои существующие тесты Cypress для визуального тестирования. Как упоминалось ранее, я буду использовать Percy для этого примера из-за его простоты интеграции. Хотя это решение SaaS, многие части по-прежнему предоставляются с открытым исходным кодом, и есть бесплатный план, которого должно быть достаточно для многих проектов с открытым исходным кодом или других побочных проектов. Однако, если вы чувствуете себя более комфортно, работая полностью самостоятельно, используя инструмент с открытым исходным кодом, вы можете попробовать Visual Regression Tracker.

Это руководство даст вам только краткий обзор Перси, который в противном случае предоставил бы контент для совершенно новой статьи. Тем не менее, я дам вам информацию, чтобы вы начали. Если вы хотите углубиться в детали сейчас, я рекомендую ознакомиться с документацией Percy. Итак, как мы можем дать нашим тестам, так сказать, глаза? Предположим, мы уже написали один или два теста Cypress. Представьте, что они выглядят так:

 it('should load home page (visual)', () => { cy.get('[data-cy=Polaroid]').should('be.visible'); cy.get('[data-cy=FeaturedPosts]').should('be.visible'); });

Конечно, если мы хотим установить Percy в качестве решения для визуального тестирования, мы можем сделать это с помощью плагина cypress. Итак, как мы делали сегодня пару раз, мы устанавливаем его в нашу корневую папку с помощью NPM:

 npm install --save-dev @percy/cli @percy/cypress

После этого вам нужно только импортировать пакет percy/cypress в ваш индексный файл cypress/support/index.js :

 import '@percy/cypress';

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

 it('should load home page (visual)', () => { cy.get('[data-cy=Polaroid]').should('be.visible'); cy.get('[data-cy=FeaturedPosts]').should('be.visible'); // Take a snapshot cy.percySnapshot('Home page'); });

Возвращаясь к нашему файлу рабочего процесса, я хочу определить тестирование Перси как второй этап работы. В нем мы запустим скрипт npx percy exec -- cypress run для запуска нашего теста вместе с Перси. Чтобы связать наши тесты и результаты с нашим проектом Percy, нам нужно передать наш токен Percy, скрытый секретом GitHub.

 steps: # Before: Checkout, NPM, and E2E steps - name: Percy Test run: npx percy exec -- cypress run env: PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}

Зачем мне токен Перси? Это потому, что Percy — это SaaS-решение для сохранения наших скриншотов. Он сохранит снимки экрана и статус-кво для сравнения и предоставит нам рабочий процесс утверждения снимков экрана. Там вы можете одобрить или отклонить любое предстоящее изменение:

Рабочий процесс утверждения Перси
(Большой превью)

Просмотр наших работ: интеграция с GitHub

Поздравляем! Мы успешно создавали наш самый первый рабочий процесс действий GitHub. Давайте в последний раз взглянем на наш полный файл рабочего процесса в репозитории моей страницы портфолио. Вам не интересно, как это выглядит на практике? Вы можете найти свои рабочие действия GitHub на вкладке «Действия» вашего репозитория:

Вкладка Действия GitHub
(Большой превью)

Там вы можете найти все рабочие процессы, которые эквивалентны вашим файлам рабочих процессов. Если вы посмотрите на один рабочий процесс, например, на мой рабочий процесс «Тесты CI», вы сможете проверить все его задания:

Представление рабочего процесса тестов CI
(Большой превью)

Если вы хотите взглянуть на одну из своих вакансий, вы также можете выбрать ее на боковой панели. Там вы можете просмотреть журнал своих заданий:

Неудачная работа с ошибками
(Большой превью)

Видите ли, вы можете обнаруживать ошибки, если они происходят внутри вашего конвейера. Кстати, вкладка «действие» — не единственное место, где вы можете проверить результаты своих действий на GitHub. Вы также можете проверить их в своих запросах на включение:

Запросы на извлечение действий GitHUb
(Большой превью)

I like to configure those GitHub actions the way they need to be executed successfully: Otherwise, it's not possible to merge any pull requests into my repository.

Заключение

CI/CD helps us perform even major refactorings — and dramatically minimizes the risk of running into nasty surprises. The testing part of CI/CD is taking care of our codebase being continuously tested and monitored. Consequently, we will notice errors very early, ideally before anyone merges them into your main branch. Plus, we will not get into the predicament of correcting our local tests on the way to work — or even worse — actual errors in our application. I think that's a great perspective, right?

To include this testing build routine, you don't need to be a full DevOps engineer: With the help of some testing frameworks and GitHub actions, you're able to implement these for your side projects as well. I hope I could give you a short kick-off and got you on the right track.

I'm looking forward to seeing more testing pipelines and GitHub action workflows out there! ️

Ресурсы

  • An excellent guide on CI/CD by GitHub
  • “The practical test pyramid”, Ham Vocke
  • Articles on the testing trophy worth reading, by Kent C.Dodds:
    • “Write tests. Not too many. Mostly integration”
    • “The Testing Trophy and Testing Classifications”
    • “Static vs Unit vs Integration vs E2E Testing for Frontend Apps”
  • I referred to some examples of the Cypress real world app
  • Documentation of used tools and frameworks:
    • GitHub actions
    • Eslint docs
    • Шуточная документация
    • Кипарисовая документация
    • Percy documentation