Микросервисная архитектура (MSA) - правила тестирования API
Тестирование API в микросервисной архитектуре. Попробую наложить тестовые практики на особенности работы с API.
Термины:
Монолитная архитектура — весь перечень сервисов, объединенных в единое приложение. Единая база кода, много функциональности.
Микросервисная архитектура — "распиленный" монолит по сервисам или логическим единицам. Сетевое распределенное приложение, каждый микросервис отвечает за свой маленький участок работы.
API (Application Programming Interface) — набор правил для межпрограммного общения.
REST (Representational State Transfer) — это популярный архитектурный подход для создания API в современном мире. Это не протокол!
Уровни тестирования - модульное, интеграционное, e2e-тесты.
Микросервисная архитектура.
Коротко. Когда-то были приложения монолиты. Большая база кода, сложная поддержка, тяжело интегрировать нового сотрудника в разработку и новые технологии. Есть сложности с расширением по производительности, сопровождению и развертыванию. Собрались умные люди и сказали "давай распилим?".
Так получилась архитектура, основанная на микросервисах. Недостатки есть, но немного другие. Проще интегрировать новых сотрудников, т.к. объем микросервиса меньше. Легче проходит ввод новых современных технологий. Разные сервисы могут быть написаны на разных языках. Проще внедрять, сопровождать и настраивать, т.к. есть docker и k8s. Проще распределять по инфраструктуре, т.к. нет привязки к конкретным серверам. Базы данных стали меньше, понятнее и прозрачнее, т.к. у каждого сервиса свои данные и своя СУБД. Тем не менее, сложности остались. Это сетевая распределенная инфраструктура, это большое количество логических компонентов, которые надо связывать между собой через api. Это проблемы распределенных вычислений и транзакций. Сложности в оценке качества распределенной инфраструктуры и процесса тестирования в целом.
В итоге решили одни проблемы, но вырастили новые, интересные.
И основной проблемой является взаимодействие микросервисов друг с другом. И тут на помощь приходит методика унификации интерфейсов. REST API один из таких подходов. Данный архитектурный стиль предлагает унификацию интерфейсов как в сети интернет (HTTP протокол, ссылочный внешний вид, JSON для данных).
Пирамида тестирования.
Пирамида тестирования иллюстрирует различные типы тестов и их взаимосвязь друг с другом. Это упрощенная версия.
Модульные тесты (Unit-tests), проверка работы конечной логической единицы системы без взаимодействия с другими компонентами. Минусы: нет проверки связи компонентов, это дополнительный код. Плюсы: работает очень быстро и стабильно.
Интеграционные тесты — это проверка взаимодействия двух или более компонентов в окружении близком к итоговому представлению системы. Минусы: медленно, нестабильно, не сразу понятно: где ошибка. Плюсы: первый шаг к "рабочей" инфраструктуре, кое-где с заглушками.
End-to-end-тесты, максимально высокоуровневые интеграционные тесты. Из явных отличий, уже без заглушек, на инфраструктуре максимально приближенной к рабочей.
Модульное тестирование. Это работа разработчика, чтобы его уникальный модуль работал исправно. Необходимо написать юнит-тесты для проверки работы модуля. Такие тесты очень быстрые и стабильные. Отработали, ошибок нет, отлично. Отлично же? Хм... а кто сказал, что разработчик напишет правильные тесты? Надо проверять отдельно.
Что может сделать тестировщик? При наличии описания api модуля, можно тестировать через api. А он должен быть, т.к. такая архитектура. Получается тестирование черного ящика, есть описание входных параметров, есть описание выходных параметров — уже не плохо.
Если по простому — берем postman/swagger и документацию к api модуля и тестируем через запросы и анализ ответов. Периодически "играясь" с заголовком запроса и входными параметрами.
Postman — это инструмент для работы с API, который позволяет пользователю посылать запросы к сервисам и работать с их ответами. С его помощью можно протестировать бекэнд и убедиться, что он корректно работает.
Будет ли это модульным тестированием? Не факт, смотрим в документацию по api и если модуль не взаимодействует с другими компонентами системы, то можно сказать, что это модульное тестирование. У модуля может быть своя БД. Это все еще модульное тестирование или уже интеграционное? Все зависит от ситуации, но чаще все это рассматривается как компонентное тестирование. А вот если модуль использует трансляцию запросов в другие компоненты и их БД — это уже интеграционное тестирование.
Интеграционное тестирование — выбираем api, которые подходят для данного вида тестирования. Это api, которые демонстрируют взаимодействие компонентов (модулей). Подобная цепочка запросов и ответов показывает работу системы в части нескольких модулей. Т.е. делим api на модульное и интеграционное тестирование.
В чем сложность? Спецификация и реализация api могут быть не синхронизированы. Тестируем реальное поведение api и сравниваем с документацией. И... этого мало. Есть еще третья сущность, которую частенько забывают — спецификация и реализация API клиент-сервер.
Получается, что для тестирования Api используем:
- спецификацию с описанием форматов данных, всех параметров и частных моментов;
- реализацию в сервисе, который принимает запрос и реагирует на него (сервер);
- реализацию в сервисе, который вызывает данный запрос (клиент);
- эти три сущности должны быть синхронизированы всегда. Только в таком случае можно сказать, что тестирование данного API — полное.
Необходимо создать процессы, которые проверят каждый api с трех сторон.
Open API, с чего начинается архитектура.
И в этот момент мы плавно переходим к термину OpenAPI.
OpenAPI — универсальная спецификация интерфейсов для клиентов по взаимодействию с сервисами, не зависящий от языка программирования и удобен в использовании как человеком, так и машиной.
Изначально разработка спецификации под названием Swagger Specification проводилась с 2010 года компанией SmartBear. В ноябре 2015 года SmartBear объявила, что она работает над созданием новой организации OpenAPI Initiative при спонсорской поддержке Linux Foundation. 1 января 2016 года спецификация была переименована в The OpenAPI Specification, а её развитие ведётся в рамках Инициативы OpenAPI. До версии 3.0.0 это Swagger, после 3.0.0 это OpenAPI.
OpenAPI представляет собой формализованную спецификацию и полноценный фреймворк для описания, создания, использования и визуализации веб-сервисов REST. Задачей является позволить клиентским системам и документации синхронизировать свои обновления с изменениями на сервере. Это достигается тем, что методы, параметры, модели и другие элементы посредством OpenAPI интегрируются с программным обеспечением сервера и всё время с ним синхронизируются.
Для работы с OpenAPI существует большое количество инструментов. Значительная часть есть тут https://openapi.tools/.
И тут мы плавно переходим к моменту проектирования архитектуры продукта. Надо решить основной вопрос вселенной и вообще, что было раньше — курица или яйцо?
Существуют разные подходы — Code-first или API-first. С выбора подхода начинается постройка архитектуры. В микросервисной архитектуре выбирают API-first. До написания любого кода.
API-first — это подход к проектированию программных продуктов, при котором работа над интерфейсами взаимодействия (API) начинается на самых ранних этапах разработки и является основополагающей. API проектируется, документируется и согласуется до написания бизнес-логики.
Подход Code-first (от кода к API) предполагает, что сначала пишется логика приложения, а API создаётся "по факту", на базе уже существующих функций. Это проще для небольших проектов, но вызывает множество проблем в масштабируемых и распределённых системах.
Если архитектура уже есть или часть микросервисов готова (значительная часть). Тогда стоит отталкиваться от существующей реализации API и начинать разработку согласно подхода Code-first. Но, ничто не мешает дальнейшую разработку перевести в API-first, когда существующий API задокументирован, утвержден, согласован и зафиксирован.
Если у вас микросервисная архитектура — API-first ваш друг и помощник.
- Параллельная разработка;
- Ясная спецификация;
- Более стабильный и предсказуемый интерфейс;
- Генерация кода;
- Повышение качества продукта.
Готовая спецификация Open API выглядит как файл .yaml или .json.
Один файл нужен для всей архитектуры, в котором описан весь API продукта.
Создает и сопровождает файл спецификации API аналитик или архитектор и хранится он в отдельном репозитории системы контроля версий. А все команды его оттуда получают. Но, этого мало. Как уберечь команды от рассинхронизации спецификации и реализации?
openapi-diff - инструмент для сравнения двух файлов. В любой момент можно выяснить что именно поменялось и оповестить команду разработки.
Все MR спецификации (merge request) в отдельный репозиторий требуют согласования представителей групп разработки. Так команда сможет получить факт изменения и аргументацию необходимости изменений. Еще лучше, если команда получит такую информацию в момент СТАРТА согласования. Будет время для корректировки изменений.
Тестирование! Ну, наконец-то...
Универсальной стратегии тестирования не существует! Нет её и в тестировании микросервисной архитектуры. Все будет зависеть от огромного количества частных случаев разработки. Все проекты и продукты — разные и подходы к разработке тоже отличаются. Структура сервисов и команд разработки тоже добавляет массу частных случаев. Поэтому дальше будет тезисно.
Важна согласованность между командами. Хорошо, когда одна команда отвечает за несколько сервисов, можно ожидать унификации этих нескольких микросервисов. При наличии нескольких команд необходимо продумывать процессы синхронизации команд и требования к унификации архитектуры микросервисов. И лучше это сделать в начале процесса разработки.
Ротация специалистов. Если есть такая возможность, имеет смысл проводить ротацию сотрудников между командами. Да, это будет замедлять разработку, но это первый шаг к унификации работы всех команд. Что приведет к ускорению работ в дальнейшем. Важно, чтобы руководители команд понимали выгоду в ротации специалистов. А если руководители не поймут или не примут подобную выгоду — рано или поздно они останутся в одиночестве и будут решать постоянные проблемы на своем участке, что будет ярко показывать качество их работы.
Еженедельные встречи специалистов одного профиля. Тестировщики всех микросервисов раз в неделю собираются на час и обмениваются опытом и подходами. Аналитики, разработчики — тоже самое, никто им не может запретить и обмениваться опытом.
Проектирование архитектуры, общая схема продукта с API должна быть перед глазами всех специалистов. Изменения API должны анонсироваться и обсуждаться ДО момента запуска новой версии API. В случае, когда продукт становится похож на шар из ниток, стоит подумать и перерисовать схему или провести анализ и мониторинг используемых API. Это работа архитектора продукта, но косвенно касается любого специалиста.
Проектирование контуров тестирования. Необходимо несколько контуров тестирования. Процессы деплоя микросервисов и подходы к тестированию (test-plan). Будет не лишним обсудить системы логов и внедрить сквозную идентификацию контрактов (данные, передаваемые посредством API). На этапе проектирования это облегчит дальнейшую работу.
CI/CD — настроено на подготовку и развертывание сервисов в любом доступном контуре. Да, частенько забывают на встречи группы разработки звать специалистов DevOps отдела. Необходимо четко отслеживать этот момент. Пригласив DevOps-специалиста на нужную встречу можно избежать массы проблем в дальнейшем. Важна согласованность специалистов разных отделов/групп. Для DevOps тестировщики очень полезные специалисты, т.к. это первые пользователи продукта.
Swagger UI/Postman - инструменты тестирования первой очереди. Позволят начать тестирование API как можно быстрее и даже с частичной автоматизацией (Postman).
Интеграционное тестирование — важно начать как можно раньше, с первой попытки ничего работать не будет. Контуров для интеграционного тестирования должно быть несколько.
Mock/stub/fake — заглушки, используются вместо сервисов, которые еще не реализованы. Важно! Выполнять контроль версий API, можно забыть про заглушку и поменять несколько раз API. В таком случае, мы тестируем уже давно устаревшие версии.
Если в какой-то момент мы понимаем, что тестировщики не успевают, сервисов много, API много, задачи множатся. Необходимая документация откладывается, тестирование перерастает в проверку чек-листов. Всё идет к автоматизации тестирования.
Проводим постоянный анализ дефектов, возможно удастся найти слабое звено продукта. Например: сервис, группа разработки, конкретный разработчик. Усиливаем тестирование в этой части продукта. Соответственно реагируем на ухудшение качества продукта.
Настраиваем отчетность по тестированию. Устанавливаем метрики качества. Заполняем отчетность по версиям продукта или сервиса с указанием значений метрик.
Важно! Необходимо внедрять автоматизацию как можно раньше и не внедрять автоматизацию, когда идут частые и крупные изменения/обновления сервисов. Противоречие? Ага, это оно! Первым делом автоматизируем тесты по смок-тестированию. Такие тесты довольно просты и не подлежат частой переработке. Возможно понадобится изменить или усовершенствовать контуры тестирования. Авто-тесты должны работать постоянно и не требовать постоянного внимания тестировщиков. Что позволит разработчику развернуть готовый сервис, посмотреть на авто-тесты и убедиться в работоспособности сервиса.
Дальше автоматизируем компонентные, интеграционные тесты. Заводим их в TMS (Test Management System) и проводим обучение разработчиков. Так авто-тесты смогут работать без участия тестировщиков.
reportportal — бесплатный веб-инструмент для тестирования программного обеспечения. Предназначен для ускорения анализа результатов тестирования и составления отчетов.
Стоит помнить, что авто-тесты — это дорого, а часто и долго. Потребуется постоянное сопровождение авто-тестов, интеграция их в TMS, отладка. Потребуется участие тестировщика для разбора сложных случаев поломок. Особенно при ошибке на границе продукта и авто-теста.
Я уже писал про разные контуры интеграционного тестирования. Имеет смысл в контурах сделать специальные различия. Это необходимо для изменений условий тестирования. Это могут быть разные данные, заглушки, конфигурации. Цель этого всего, исключить влияние "пестицида" в условиях тестирования.
End-to-end тестирование находится на вершине пирамиды тестирования. Не устоит увлекаться одним видом тестов, особенно E2E. Это полноценный контур продукта. Если тест прошел, то скорее всего там нет ошибки и он пройдет на рабочем окружении. Дефект пойманный при E2E тестировании очень дорогой в исправлении. Дорого, медленно и трудоемко. Да, здесь будет огромная польза от продуманной системы логов. Сквозная идентификации данных может ускорить поиск причины дефекта.
Тестирование оплаты. Зависит от провайдера услуг оплаты. Как правило, предоставляется тестовый шлюз, идентичный рабочему. Плюс, выдаются данные карт, которые "работают" в тестовом шлюзе. Подобные шлюзы как правило отлажены на 100%, никаких дополнений и изменений в них не ожидается. И главное, что работает на тестовом шлюзе будет работать на рабочем. Провайдер платежных услуг в этом крайне заинтересован.
Генерация кода из спецификации API. Да, такие генераторы есть и используются. Надо отдавать себе отчет, кто именно этим пользуется. Одно дело, если это разработчики для реализации API в сервисах. Другое, когда авто-тестировщики генерируют клиентов согласно спецификации. Это отдельный тестовый фреймворк, который использует генерированный код по вызову API. Это отдельная и довольно сложная задача. Особенно тяжело будет сделать подобное при существующем работающем продукте. Потребуется досконально изучить весь продукт. Это будет долго и очень дорого. И не исключено, что данное решение придется отдельно тестировать. Тесты на тесты! А это уже излишне. Но, если у вас отличная команда разработчиков, которые смогут помочь тестировщикам — это сможет работать. Либо, у вас должен быть богатый штат отличных авто-тестировщиков (разработчиков авто-тестов).
Если тестирование запускается на этапе, когда микросервисная архитектура разработана и реализована, но... как-то разрабатывали без тестировщиков. Достигли десятки микросервисов и что-то плохо это все работает. Тестировать такое можно. Правда, результат будет не быстро. Стоит ознакомиться с требованиями и архитектурой продукта, а также со спецификацией API. После чего, можно распараллелить работы по подготовке тест-плана и тест-кейсов и отдельно, развертывание и внедрение swagger UI/postman для мануальных тестов. Эти инструменты должны уже присутствовать в разработке и это не сложно. Смок-тесты можно будет настроить в postman как авто-тесты.
Строим тестирование начиная со смок-тестов, далее компонентное тестирование и интеграционное. Стоит помнить, что интеграционные тесты необходимо запустить как можно раньше (в этом случае на уровне смок-тестов).
Тестирование существующего продукта потребует от группы контроля качества усидчивости и умения работать с огромным объемом данных. Предстоит работать параллельно, где-то тестируешь, где-то изучаешь требования и архитектуру, где-то ищешь подходящие инструменты. Что потребует серьезных компетенций и опыта от сотрудников группы контроля качества.
Итоги:
Для усиления контроля качества микросервисной архитектуры стоит обратить внимание на:
- группа контроля качества на продукт, с ротацией, с обменом опытом работы на разных микросервисах. Сбор и внедрение лучших практик. Избегать долгой работы тестировщика над одним микросервисом.
- openAPI спецификация, подход API-first. Отдельный репозитарий, изменения с ведома лидеров групп разработки.
- несколько контуров для тестирования.
- CI/CD до контуров тестирования.
- swagger UI/postman для тестирования и начальной автоматизации тестирования, оценка покрытия тестами.
- логи со сквозной идентификацией пакета данных для облегчения поиска причины дефекта.
- mock/stub/fake в дозированном виде с четким пониманием версионирования и актуальности.
- смок, компонентное, интеграционное тестирование. Интеграционное тестирование как можно раньше.
- E2E тестировать надо, но не упарываться.
- автоматизация тестирования в разумных пределах, по возможности как можно раньше. Учитывать, что это дорого и долго. Все зависит от бюджета и состава группы разработки.
Часто рядовые разработчики или тестировщики не верно оценивают качество продукта. Допустим — у нас раз в полгода падает рабочая версия продукта, приходится выходить во внерабочее время и искать неисправности, срочно править и т.д. Тут есть проблема в недосказанности руководства — почему сложилась такая ситуация и насколько она плоха. Возможны разные варианты. Нет бюджета для расширения штата, закупки/аренды оборудования и прочего. Нет специалистов необходимого уровня компетенций, опять же из-за бюджета или по политической причине. Или... банальное, это отличное качество продукта. То, что рабочая версия "падает" раз в полгода ВСЕГО, позволяет держать 99% рабочего времени без отказов. И этого достаточно! О другом качестве договора не было. Для данного участка, для данного заказчика, для данного продукта и по сравнению с другими продуктами и общим качеством ПО — этого достаточно. Так может быть и проблема руководства это доносить до разработчиков, что это является нормой. А если продукт "падает" раз в месяц — это нормально? Может быть и да, почему нет то... По итогу никто не будет расширять группу контроля качества или проводить автоматизацию тестов — это ненужные затраты по бюджету.
Автоматизация и её проблемы — это не панацея! Автоматизация процедур проверки качества несет проблемы. Частично я о них писал выше:
- Это долго и дорого. Нужно четко понимать, что продукт "играет в долгую" и автоматизация необходима.
- Синдром пестицида, когда процедуры "привыкают" к тестируемым данным и составу тестового стенда и уже не отвечают задачам проверки и контроля.
- Деградация мануальных тестировщиков, они разучиваются тестировать то, что автоматизировано. Не надо уже руками тестировать.
- Повышенное доверие к автоматическому тестированию от разработчиков. Они рассматривают это как очередные юнит-тесты, а это не так. Юнит-тесты простые, быстрые и очень стабильные. Это код для кода. Автоматизация тестирования — это код для проверки функциональности.
- Версионирование тестов и артефактов тестирования.
- Не мгновенные правки и внесение изменений. Постоянный режим сопровождения авто-тестов.
- Существует болезнь проектирования тестов на авто-тесты.
- и прочее
Эта статья не универсальная таблетка, которая поможет всем и четко скажет, что делать. Но, если отталкиваться от написанных рекомендаций и шаг за шагом улучшать процессы тестирования — всё должно получиться. Все продукты и проекты разные и невозможно написать идеальные рекомендации, которые подойдут всем. У кого-то продукт из 50 микросервисов не синхронизируется. У кого-то бюджет есть ровно на 2 программиста и одного аналитика, а на тестировщиков бюджета даже в планах нет. Кто-то выхватил джек-пот и ему необходимо отмасштабировать существующий продукт на несколько порядков, а к этому никто не готов и даже в мечтах этого не было.
В идеальной ситуации, если развивать контроль качества с начала разработки, это окажется проще и значительно дешевле. По сравнению, когда уже что-то сделали, оно странно себя ведет и приносит массу проблем. Реалии всё расставляют по своим местам. Никто не может заглянуть в магический шар и увидеть, что получится из проекта через 2 года или 5 лет.