Continuous Testing в CI/CD: что это, зачем нужно и как работает

Тестирование — один из процессов, который может быть автоматизирован в рамках CI/CD. Надёжное и тщательное автоматизированное тестирование позволяет быть уверенным в новых сборках, снижает затраты на производство и повышает качество продукта. Но даже в крупных компаниях на больших проектах оно есть не всегда. 

Обычно в тестирование начинают вкладываться, когда багов становится слишком много, недовольство клиентов растёт, и начинают «гореть» деньги бизнеса. Вместе с Александром Довнаром, Lead DevOps в Naviteq, мы разобрали, что такое непрерывное тестирование и какую роль оно занимает в CI/CD. А ещё рассмотрели кейс, как компании приходят к его внедрению, и что это внедрение даёт. 

59be7952da4ed457cbf6421cb044b409.jpg

Непрерывная интеграция (CI) и тестирование

Практически все подходы к разработке программного обеспечения итерационные. Это значит, что команды двигаются 2–3-недельными спринтами, с каждым спринтом добавляя в продукт новые возможности. Работа над разными задачами ведётся параллельно, а кодовые базы разработчиков могут пересекаться. Чтобы это не приводило к багам и поломкам, внедряется CI-процесс.

Основная задача CI — сделать так, чтобы по мере параллельной работы над одной или разными кодовыми базами в конечном счёте получилась версия приложения, которую можно доставить в окружение. Для этого каждый кусок кода должен быть версионирован, протестирован и упакован в подходящий формат. 

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

Непрерывная доставка (CD) и тестирование

Есть два варианта расшифровки аббревиатуры CD — continuous delivery и continuous deployment. 

Continuous delivery или непрерывная доставка — процесс, по окончании которого мы можем нажать на кнопку и доставить новую версию приложения нашим клиентам.

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

Из чего состоит CD: после CI у нас есть работающая версия приложения, мы разворачиваем в её разных окружениях и запускаем набор тестов. Обычно таких окружений три (но всё зависит от вашей схемы работы с системой контроля версий GIT и релизного процесса):

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

  • Далее ветка, где велись изменения, сливается с основной веткой. И версию приложения, получившуюся после этого слияния, мы разворачиваем в staging окружении. На этом этапе мы запускаем E2E-тестирование (end-to-end тесты для проверки полного функционала), плюс, дополнительно обычно работает мануальный тестировщик, который будет проверять наше приложение как реальный пользователь. Также могут проводиться разнообразные security-тесты.

  • По завершении тестов мы говорим, что версия приложения стабильна, не имеет багов и готова к развёртыванию в продуктовой среде. Дальше всё зависит от того, какой процесс релизов установлен в команде. Мы либо разворачиваем всё вручную по кнопке, либо это происходит автоматически по наступлению какого-то события. В конце мы запускаем ряд тестов и просим проверить функционал наших тестировщиков и (или) реальных пользователей (например, если они готовы быть Beta-тестировщиками, и у нас есть Feature toggling в приложении). Далее следим за количеством ошибок в системах мониторинга и логах наших приложений, чтобы отловить потенциальные проблемы.

Окружений может быть больше, например, если мы собираемся проводить performance- и расширенные security-тесты. Запускать их на одном из трёх перечисленных окружений, значит потерять его на время, поэтому для них выделяют отдельные окружения. 

Непрерывное тестирование (CT)

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

В CI-фазе важно, чтобы сборка проходила быстро, поэтому чаще всего применяют облегчённые типы тестов:  

  • unit-тесты — чтобы протестировать отдельные компоненты;

  • интеграционные тесты — чтобы проверить интеграцию этих компонентов;

  • базовый линтинг — чтобы проверить код на соответствие тому, как мы договорились писать его внутри команды;

  • статистический код-анализ — чтобы отловить потенциальные уязвимости в нашем коде;

  • smoke-тесты — чтобы проверить, развернулось ли приложение, и корректно ли работают его базовые компоненты. 

Можно делать больше тестов, но обычно этих 5 при условии, что они хорошо написаны, достаточно. Запустив их, мы уже предупредим около 90% багов на стадии CI.

На стадии CD идёт непрерывное тестирование конкретных окружений, поэтому тестов становится больше, и они дольше по времени:  

  • E2E-тесты — чтобы проверить корректность работы UI;

  • performance-тесты — чтобы проверить, нет ли просадок по производительности;

  • регрессионные тесты — чтобы убедиться, что мы не вернулись к багам, исправленным в прошлом, перед выходом релиза на продакшн-среды;

  • security-тесты, «ломающие» наше приложение — чтобы проверить, что у нас нет уязвимостей;

  • penetration-тесты — чтобы проверить устойчивость приложения к взломам и отражению DDoS атак. 

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

Разработка стратегии тестирования — работа не только опытных тестировщиков, но и DevOps-инженеров. Тесты являются частью CI/CD, поэтому специалисты, реализующие DevOps, тоже должны участвовать в их создании. Ещё не обойтись без представителей бизнеса, которые должны дать на всё это деньги. Разработка непрерывного тестирования — это долго и дорого, но в долгосрочной перспективе она даёт невероятные результаты. 

Как понять, что пора проводить тестирования

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

Постепенно они находят инвестиции, и их MVP начинает обрастать расширенным функционалом. Заниматься разработкой вдвоём становится сложно, они нанимают 4 фронтенд-разработчика и 6 бэкенд-разработчиков. Команда из 10 разработчиков может работать параллельно над разным функционалом, поэтому на этой стадии развития логично внедрить контейнеризацию и CI. Тогда локальные стенды, на которых тестируется функционал, будут отражать реальную ситуацию в конечных окружениях. 

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

Дальше есть два пути развития:  

  • либо очень много работать и постоянно исправлять стихийно появляющиеся баги, чтобы не потерять клиентов;

  • либо выделить по одному разработчику из команд фронтенда и бэкенда, чтобы они начали покрывать тестами существующую кодовую базу. А ещё договориться внутри, что теперь весь новый функционал будет покрываться хотя бы unit-тестами. 

Второй вариант позволяет защитить себя от самоошибок, которые часто появляются при разработке, и способствует развитию — команда понимает пользу unit-тестов и постепенно внедряет интеграционное тестирование, улучшает стабильность и качество релизов. 

Стартап продолжает масштабироваться, штат растёт, появляются новые команды. Помимо веб-версии, продукт обзаводится версиями для iOS и Android, и тестов требуется больше. Разработчики не любят тестировать код, и тогда им на помощь приходят инженеры, специализирующиеся на таких задачах, — тестировщики. Они начинают отлавливать ошибки вручную и внедрять автоматизированные тесты.

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

Коротко о главном: зачем нужно непрерывное тестирование

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

  • Быстрые и стабильные релизы. Благодаря непрерывным циклам обратной связи, вы рано находите баги и оперативно исправляете их. Время на разработку и выпуск релиза сокращается. 

  • Высокая эффективность. За счёт автоматизации ресурсы команды расходуются более рационально. Разработчики могут сосредоточиться на разработке, а тестировщики — отказаться от повторяющихся задач в пользу задач, требующих критического и творческого мышления. В результате охват и качество тестов могут быть увеличены. 

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

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

Для тех, кто хочет научиться работать с CI/CD и автоматизировать тестирование

20 июня в Слёрм стартует усовершенствованный курс »CI/CD на примере Gitlab CI». Вы пройдёте путь от создания самого простого пайплайна до настройки сложных вариантов CI/CD с возможностью отката на предыдущую версию.

Посмотреть программу и записаться: https://slurm.club/3NvNhSb

© Habrahabr.ru