Интеграционное тестирование нередко вспоминают на собеседованиях, когда спрашивают о видах и уровнях тестирования. И, как любую теорию, его сложно понять в отрыве от практики. В этой статье разбираем тестирование интеграций на конкретных примерах.
Что это такое?
Не поверите, но интеграционное тестирование – это тестирование интеграций :) А интеграция – это любое взаимодействие частей внутри целого. В нашем случае взаимодействуют модули какого-либо ПО: веб-сайта, мобильного приложения или API.
Отдельные модули тоже необходимо тестировать. Иначе нет смысла проверять, как работают вместе заведомо дефектные части. Но модульное тестирование кода (оно же unit-тесты) чаще всего проводят сами разработчики.
Интеграционное тестирование стоит на уровень выше модульного, и к нему уже могут подключаться QA-инженеры. Где же найти интеграции на своем проекте? Если совсем коротко – всё есть интеграция :)
Интеграции – внутренние и внешние
Итак, как могут выглядеть внутренние интеграции?
Самый очевидный пример – фронтенд и бэкенд. Возьмем фильтры в интернет-магазине. Пользователь заходит в каталог и ставит чекбокс “Доставка в течение 24 часов”. В ответ он получает список из товаров, которые могут доставить ему за сутки.
Так вот чекбокс, его расположение, внешний вид и эффекты – это фронтенд. А процесс фильтрации – это бэкенд, который по API получил запрос от фронта, обработал его и “сообразил”, какие именно товары нужны. После этого бэк сформировал запрос к базе данных, забрал карточки тех товаров, которые соответствуют фильтру, и передал информацию на фронтенд.
Другой простой пример: бэкенд и база данных. Допустим, в интернет-магазине нужно создать личный кабинет, чтобы сделать покупку. Пользователь заполняет форму регистрации, нажимает кнопку – и получает готовый личный кабинет. Это значит, что микросервис, отвечающий за регистрацию новых юзеров, обработал данные пользователя и отправил запрос в базу данных. По этому запросу в БД создалась новая сущность — аккаунт пользователя.
Менее очевидный пример: взаимодействие нескольких микросервисов. Как может выглядеть такая интеграция?
Допустим, пользователь заходит на сайт интернет-магазина, в котором ассортимент зависит от города. В таком случае, как только пользователь нажимает на сайте кнопку “Каталог”, запрос с фронтенда отправляется в микросервис каталога.
Тот в свою очередь должен обратиться к другому микросервису — который запрашивает и обрабатывает данные о геолокации пользователя. Как только микросервис геолокации сообщил, где пользователь находится, микросервис каталога отправляет запрос в базу данных с учетом информации о местонахождении пользователя. Как результат – на сайте отображаются только те товары, которые доступны в городе пользователя.
А еще бывают интеграции между микросервисами и брокерами сообщений. Например, владелец банковской карты получает в своем приложении пуш-уведомление. Что может происходить в этот момент “под капотом”?
Микросервис, отвечающий за отправку уведомлений, сначала отправляет данные брокеру. Тот формирует из данных сообщение и ставит его в очередь – это и есть взаимодействие микросервиса и брокера. В дальнейшем сообщение забирает из очереди другой микросервис, который отправляет пуши только определенному списку пользователей.
Брокеры сообщений – это программы-посредники, через которые общаются составные части сайта. Брокеры получают данные (сообщения) от одного компонента (producer), формируют из этих данных очередь и передают данные другому компоненту (consumer). Или же consumer забирает данные самостоятельно, исходя из определенных маркеров, которыми помечены сообщения. Из брокеров всех на слуху Kafka или RabbitMQ, но существует больше 30 аналогов.
А что насчет внешних интеграций?
Самые распространенные примеры – авторизация через сторонние сервисы и оплата товаров или услуг.
В случае с авторизацией создается интеграция между приложением и сторонним сервисом – например, Яндекс или VK. Приложение как бы делегирует процесс аутентификации тому сервису, где у пользователя уже есть аккаунт. А сервис в свою очередь дает приложению ограниченный доступ к данным пользователя, которые у него хранятся. Как выглядит этот процесс на примере книжного магазина:
пользователь нажимает на сайте книжного магазина кнопку “Войти с помощью Яндекс ID” – открывается окно авторизации, принадлежащее уже не книжному, а Яндексу
если пользователь еще не авторизован под своим Яндекс-аккаунтом, он вводит логин и пароль, серверы Яндекса находят его аккаунт в своих базах данных
когда вход в Яндекс-аккаунт осуществлен, Яндекс спрашивает у пользователя: “Можно я немного расскажу о тебе книжному магазину?”
если пользователь дает согласие, Яндекс через систему токенов дает книжному магазину доступ к некоторым данным пользователя – например, к его имени и электронной почте
В дальнейшем книжный магазин даже может обновлять эти данные через API Яндекса – так что если пользователь сменит имя в своем Яндекс-аккаунте, в его аккаунте для книжного магазина имя тоже поменяется.
Второй пример внешней интеграции – оплата товаров и услуг через Интернет. Онлайн-магазины не занимаются обработкой и проведением собственных платежей, вместо этого они подключают банковский эквайринг.
В таком случае раздел, отвечающий за покупку на сайте, интегрируется с банком через платежный шлюз. Когда пользователь нажимает кнопку “Оплатить” в онлайн-магазине, он попадает на страницу платежа, предоставленную банком, и вводит данные своей карты. В этот момент платежный шлюз передает банку реквизиты продавца, покупателя и сумму покупки.
А банковская система, получив все эти данные, приступает к проверке: подходящая ли у покупателя платежная система, достаточно ли у него денег на карте, возможно ли осуществить платеж. Если все успешно, деньги переводятся от банка покупателя к банку продавца.
А как протестировать интеграции?
При тестировании интеграций важно не забыть, что мы проверяем в первую очередь связь между двумя частями целого. Это значит, что наше действие в одной части обязательно должно откликаться определенным образом в другой.
Например, когда мы фильтруем каталог, нужно проверить не просто отработку чек-бокса на фронте, но и результат: соответствуют ли товары установленному фильтру? Если да, интеграция корректная. Если нет, можно приступить к локализации бага: посмотреть запрос с фронтенда и ответ от бэкенда.
А при создании профиля пользователя через форму регистрации важно сделать запрос в базу данных и посмотреть – появился ли такой аккаунт и правильно ли заполнены значения в столбиках БД? Как вариант – можно авторизоваться под этим аккаунтом на сайте, но только если авторизация уже создана и работает корректно.
Или возьмем пример внешней интеграции – авторизация на сайте книжного магазина через Яндекс ID. Как могли бы выглядеть проверки именно с точки зрения интеграционного тестирования?
Для начала обратимся к документации сервиса, с которым интегрируется наш сайт. У Яндекса она будет выглядеть вот так. Обратите внимание, что в блоке “Совет” рассказывается про отладочные токены, которые можно использовать в тестировании.
Аналогичные базы знаний можно найти при тестировании оплат через эквайринг. Например, YooMoney и Cloudpayments позволяют проводить тестовые платежи, и в их документации можно найти данные тестовых банковских карт.
Затем переходим к базовым тест-кейсам. Посмотрим на позитивный сценарий: пользователь уже авторизован в сервисе Яндекса и дает разрешение на использование своих данных – авторизация на сайте книжного должна пройти успешно.
Потом более сложный: пользователь еще не авторизован в Яндексе, но вводит все свои данные корректно и разрешает их использовать – авторизация на сайте книжного должна пройти успешно.
Далее можно пробовать негативные проверки: пользователь авторизован, но не дал разрешения на использование своих данных – авторизация на сайте книжного магазина должна быть прервана. Или пользователь не авторизован в Яндексе, вводит корректные данные, но запрещает их использование – авторизация прерывается.
Также важно проверить, в каком объеме и какие именно данные передаются сайту книжного от Яндекса. Например:
Достаточно ли передаваемых Яндексом данных для создания аккаунта на сайте книжного магазина?
Что произойдет, если каких-то данных, необходимых книжному, в аккаунте Яндекса просто нет? Например, в профиле магазина обязательно указывать свой домашний адрес, а Яндекс-аккаунт пользователя не содержит этой информации.
А что если изначально данные, обязательные для книжного, присутствовали, а затем пользователь удалил их из своего Яндекс-аккаунта?
Во всех случаях, когда данных недостаточно либо они по каким-то причинам не подходят для создания аккаунта на сайте книжного магазина, пользователю должно прийти явное и недвусмысленное сообщение об ошибке.
А еще стоит посмотреть, будет ли аккаунт пользователя на сайте книжного магазина обновляться вслед за обновлением аккаунта на Яндексе. Если пользователь сменил аватар, имя, почту или любую другую информацию о себе, отобразится ли обновление в аккаунте магазина?
Добавим немного теории, которую будут рады услышать на собеседовании. Существует несколько методов тестирования интеграций, самые популярные из них:
Инкрементальный – тестируются сначала только два логически связанных модуля, а затем к ним постепенно прибавляются новые модули. Например, сначала проверяется связка бэкенда и базы данных – то есть тестируется запрос API, который создает сущность в БД. Только затем подключается тестирование фронтенда, к которому “привязывается” запрос на бэкенд.
Инкрементальный метод в свою очередь бывает восходящий и нисходящий – то есть можно начинать тестирование либо от низкого уровня модулей, переходя к высокому, либо наоборот.
“Сэндвич” – одновременно сочетаются нисходящий и восходящий методы.
“Большой взрыв” – все модули собираются вместе и тестируются как единое целое. По факту именно он применяется чаще всего.
Еще одно понятие, которое точно пригодится на практике – заглушка (mock). Заглушка – это программа, которая имитирует поведение вызываемого нами модуля.
Например, нужно протестировать работу интерфейса корзины, к которой пока что не подключён банк. При этом у нас уже есть документация, в которой прописан механизм работы эквайринга. В таком случае разработчик может установить заглушку, которая будет выдавать успешный результат либо ошибку оплаты в зависимости от наших действий в корзине.
Еще встречается такое понятие, как драйвер. Оно редко применяется на практике, но встречается в ISTQB-глоссарии терминов (поэтому может быть полезно для собеседования). Драйвер – это программа, которая имитирует вызов к тестируемому модулю, по сути это противоположность заглушки.
Например, нам нужно посмотреть, корректно ли служба поддержки интегрирована с админ-панелью. Если фронтенд поддержки при этом не готов, разработчик может установить драйвер, который будет имитировать запросы пользователей, и мы увидим, как они отображаются в админке.
А какие есть инструменты для тестирования интеграций?
Существует не так много программ, которые специализируются именно на интеграционном тестировании. В зависимости от того, какая интеграция проверяется, полезными могут оказаться любые инструменты, показывающие процесс передачи данных между частями приложения – Devtools, Postman, логи или снифферы.
Также существуют UI-инструменты, которые позволяют проще взаимодействовать с брокерами сообщений – работать с очередями, искать топики, просматривать сообщения. Среди самых популярных – Offset Explorer, Kafka Ui, Rabbit MQ Management.
А для баз данных используются программы наподобие DBeaver, которые позволяют управлять БД через понятный интерфейс.
Отдельно выделим Jaeger – программу, которая позволяет отслеживать перемещение данных по компонентам системы. Если у приложения микросервисная архитектура, то через Jaeger мы можем увидеть путь запроса по различным микросервисам. Такое отслеживание ещё называется трассировкой.
При трассировке четко видно, как взаимодействуют разные модули – а значит можно точнее определить источник бага или загадочной 500-ки. Например, в Jaeger отображаются SQL-запросы, которые сервер делает в базу данных.
И если система отправляет неверный запрос или возвращает неверный ответ, тестировщик может это обнаружить и сообщить разработчику. К тому же Jaeger замеряет скорость работы компонентов, что может пригодиться для оптимизации.
Два основных понятия в интерфейсе Jaeger – это span и trace. Спан – это один “шаг” запроса, одна операция. В информации о спане можно посмотреть, на каком сервисе операция происходит и какое время она занимает.
А трейс – это совокупность спанов, которые проходит запрос. По сути это весь путь запроса от начала (родительского спана) до завершения (через дочерние спаны). У каждого трейса есть ID, по которому его можно отслеживать и находить в других сервисах. Узнать trace ID можно в заголовках ответа, который приходит на интересующий нас запрос.
В QA Studio мы учим работать с Jaeger на примере Битвы покемонов — веб-приложения, которое мы создали специально для курса. В приложении существует рейтинг игроков, который рассчитывается на основе данных из трех компонентов системы – монолита и двух микросервисов. Студенты учатся отключать кэш бэкенда, отслеживать путь запроса по различным поддоменам и разбираться в данных, из которых формируется рейтинг.
Больше о Jaeger можно узнать из видео на нашем YouTube канале.
Но может случиться, что на вашем проекте не подключен Jaeger. Тогда однозначно помогут логи – их можно просматривать, например, через Kibana, Graylog, частично – через Sentry. Если модули интегрированы неверно, в логах Kibana можно постараться найти “виновника” ошибки. Это непросто, придется просматривать логи каждого микросервиса отдельно – но все-таки возможно :)
А Sentry позволяет отслеживать сбои в реальном времени и делиться ссылками на них с разработчиками. Не всегда получится определить причину бага самостоятельно, и, строго говоря, такой задачи перед ручным тестировщиком не стоит, но попытаться стоит. Как минимум, если мы передаем максимально полную информацию о баге, прикрепляем логи, разработчики смогут быстрее локализовать сбой в интеграции.
Если проект небольшой и тестировщик может локально развернуть его через Docker, то посмотреть логи можно в одном из внутренних инструментов – Docker Compose.
Также в случае, если завязанная на интеграцию фича находится в разработке, можно самостоятельно создать мок-сервер через различные инструменты – например, Postman, WireMock или Mockoon. С их помощью мы можем сделать искусственный сервер, который будет возвращать нужные данные на тестируемый фронтенд. А вот перенаправлять запросы так, чтобы они приходили на мок вместо реального сервера, можно уже с помощью Charles – через функцию Map Remote.
Описанный выше вариант подходит, если интерфейс приложения уже создан, а микросервис, который выводит на него данные – еще нет. Если же нам нужно, чтобы не интерфейс сайта, а один из микросервисов отправлял запросы в заглушку, стоит обратиться к разработчикам – они смогут перенастроить конфигурации проекта для нужд тестирования.
Вместо итога
Ручной тестировщик неизбежно сталкивается с тестированием интеграций – хотя в моменте может и не осознавать, что занимается именно интеграционным тестированием :)
Надеемся, приведенные выше примеры помогут вам чуть больше понять, что же такое интеграционное тестирование, а инструменты пригодятся в работе <3
ProTestingInfo_QA
+1 для продвижения статьи!
Полезная статья.
Тоже у себя порекомендую !
German_D Автор
Спасибо : )