UI + API как единый интеграционный контур
Привет! Меня зовут Артем, я 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 естественно развивает подходы, описанные в предыдущих статьях.