Привет! Меня зовут Артем, я QA full-stack в команде TData. Мы занимаемся разработкой высоконагруженных корпоративных решений. Для нас автоматизация тестирования - это не просто способ снять нагрузку с ручных тестировщиков, а важная часть инженерной культуры.
UI + API как единый интеграционный контур: опыт RT.ClusterManager и RT.WareHouse
Вместо разрозненных UI- и API-тестов мы построили единый контур: UI создает сущности, API проверяет их через RestAssured, а SSH подтверждает состояние на хостах.
Один сценарий - три уровня проверки.
В этом примере я расскажу о реализации на базе RT.ClusterManager (СМ) - системы управления кластерами и их конфигурацией - RT.Warehouse (WH), который через СМ поднимает и обслуживает кластеры хранилища данных на реальных серверах.
Почему раздельные тесты больше не работают
В типичном проекте тесты функционируют обособленно:
UI-тесты проверяют логин, клики, видимость элементов. Создают кластер через форму, но не убеждаются, что он реально появился в API.
API-тесты проверяют статусы и тело ответа, но работают с «чистыми» данными, созданными напрямую через API, без участия UI.
Инфраструктура проверяется вручную по SSH: Wal-G и конфиги видны в UI, но не подтверждаются на уровне ОС.
В результате:
UI создал кластер, но API-тест не знает его ID и имя - приходится хардкодить или использовать моки.
API подтверждает, что «что-то» существует, но нет гарантии, что это создано через UI.
Настройки провайдера и Wal-G видны в интерфейсе, но не проверяются на реальных хостах.
С этой проблемой мы столкнулись в RT.ClusterManager: нужно было проверять не только кнопки и API-ответы, а весь путь - от действий пользователя в UI до фактического состояния инфраструктуры.
Идея: единый интеграционный контур
Мы объединили три уровня в одном сценарии:
UI (Selenide): создаем провайдеры, кластеры, настраиваем плагины, добавляем хосты.
API (RestAssured): проверяем те же сущности через REST - списки, поля, статусы.
SSH: выполняем команды на хостах и проверяем реальное состояние - процессы, конфиги, логи.
Данные создаются в UI, переиспользуются в API и подтверждаются на уровне ОС.
Один набор констант - для всех уровней.
Как это выглядит на практике: RT.WareHouse + Wal-G
1) Подготовка (@BeforeAll / @BeforeEach)
@BeforeAll public static void setupOnce() { rtSystemPlugin = downloadPlugin("rt.system:RT.System-1.6.0"); wareHousePlugin = downloadPlugin("rt.warehouse:RT.WareHouse-2.13.10"); } @BeforeEach public void setup() { Selenide.open("/login"); loginPage.authorization(LOGIN_USERNAME, LOGIN_PASSWORD); barPage.avatarShouldExist(); }
2) UI: создание провайдера и кластера
InfrastructureManager.addPluginWh(rtSystemPlugin); InfrastructureManager.addPluginWh(wareHousePlugin); InfrastructureManager.createProviderWithHostsWh( PROVIDER_NAME_WH_INTEGRATION1, PROVIDER_DESCRIPTION_INTEGRATION ); InfrastructureManager.validateHostsWh(); InfrastructureManager.createClusterWhWithPluginVersion( wareHousePlugin, CLUSTER_NAME_WH_INTEGRATION, CLUSTER_DESCRIPTION_INTEGRATION ); InfrastructureManager.setUpConfigInClusterForPluginsWhOnRedos(); InfrastructureManager.setUpWalgBackupConfGp(); InfrastructureManager.addHostAndInstallGp();
3) Терминал: настройка NFS и проверка на хостах
infrastructureManager.executeCmTerminalCommands(); // NFS на CM infrastructureManager.executeM1AndS1TerminalCommands(); // NFS на M1, S1 infrastructureManager.verifyAllTerminalCommandsResults(); // проверка скриптов, /backup
4) UI: финальная проверка (Run Wal-G)
InfrastructureManager.clickOnRunWalgAndCheckVisibleSuccessfulRunWalg();
Технический стек
UI: Selenide, Page Object
API: RestAssured, TokenManager
Терминал: JSch, RemoteCommandExecutor
Сборка/отчеты: Gradle, Allure
Общие данные: единые константы (имена, URL, креды, хосты)
API-слой в этом контуре
API-тесты остаются в отдельных классах, но работают с теми же данными. Пример:
@BeforeEach public void auth() { Response response = TokenManager.getToken( ApiConfig.getDefaultUsername(), ApiConfig.getDefaultPassword() ); this.token = TokenManager.extractToken(response); } Response response = given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) .when() .get("/cluster") .then() .statusCode(200) .extract().response();
В интеграционном сценарии после создания кластера через UI добавляется API-проверка полей и статусов. Это подтверждает, что UI и API работают с одной и той же сущностью.
Плюсы подхода
Ловим ошибки на стыке UI, API и инфраструктуры.
Снижаем дублирование: один набор данных на все уровни.
Ближе к реальным пользовательским сценариям.
Быстрее локализуем причину падения:
UI создал, API не видит → проблема API/БД.
API видит, а на хосте пусто → проблема деплоя/конфигов.
Минусы и сложности
Интеграционный тест может идти 20–30 минут.
Сильная зависимость от стенда: ВМ, сеть, SSH.
Сложная конфигурация (хосты, URL, креды, переменные окружения).
Рекомендации
Выносите общие данные в константы, не хардкодьте в тестах.
Разделяйте быстрые и долгие сценарии.
Используйте единый источник правды для хостов и URL (конфиги + env).
Логируйте шаги и собирайте Allure-отчеты.
Как эта статья продолжает предыдущие
Эта статья логично опирается на две предыдущие:
«Автоматизация тестирования, которая не ломается при первом редизайне»
«Интеграционные тесты: когда UI-автотесты проверяют не только кнопки, но и всю систему целиком»
Здесь следующий шаг: к UI и интеграционным тестам добавляются API и SSH, чтобы получить сквозной контур проверки.
Вывод
Контур UI → API → SSH дает целостную картину работы системы.
На примере CM/WH такой подход позволяет проверять не только интерфейс, но и фактическое состояние инфраструктуры после действий в UI.
Единый набор данных и общая конфигурация упрощают поддержку, а связка UI+API+SSH естественно развивает подходы, описанные в предыдущих статьях.
