Facade (Фасад)

Проблема

Подготовка тестовых данных через API — распространённая задача. Чтобы создать пользователя с заказом, тест вынужден работать напрямую с несколькими API-клиентами: UserApi, OrderApi, PaymentApi, InventoryApi. Каждый вызов — своя сигнатура, свои исключения, своя последовательность. Тестовый метод превращается в набор низкоуровневых HTTP-вызовов, не связанных с тестируемым сценарием.

Facade предоставляет упрощённый интерфейс к сложной подсистеме. TestDataFacade скрывает за одним методом всю цепочку API-вызовов. Тест вызывает facade.createUserWithOrder(...) и получает готовые данные — не зная, сколько HTTP-запросов было сделано «под капотом».

Структура модуля

facade/
├── build.gradle
└── src/
    ├── main/
    │   └── java/
    │       └── dev/shipovalov/facade/
    │           ├── TestDataFacade.java          # Фасад: упрощённый API для подготовки данных
    │           ├── api/
    │           │   ├── UserApi.java             # Клиент API управления пользователями
    │           │   └── OrderApi.java            # Клиент API управления заказами
    │           └── model/
    │               ├── User.java                # Модель пользователя
    │               └── Order.java               # Модель заказа
    └── test/
        └── java/
            └── dev/shipovalov/facade/
                └── FacadePatternTest.java       # Тест, использующий только фасад

Ключевые классы

Класс Назначение
UserApi Низкоуровневые операции: создать, получить, удалить пользователя через HTTP
OrderApi Низкоуровневые операции: создать заказ, добавить позиции, подтвердить
TestDataFacade Оркестрирует вызовы UserApi и OrderApi, предоставляет методы уровня бизнес-сценария
FacadePatternTest Тест работает только через фасад, не зависит от деталей API

Сравнение подходов

// Без фасада — тест знает о деталях каждого API
UserApi userApi = new UserApi(baseUrl, token);
OrderApi orderApi = new OrderApi(baseUrl, token);

User user = userApi.createUser(new CreateUserRequest("john", "john@example.com", "USER"));
userApi.activate(user.getId());
Order order = orderApi.createOrder(new CreateOrderRequest(user.getId()));
orderApi.addItem(order.getId(), "PRODUCT-42", 2);
orderApi.confirm(order.getId());
// И только теперь можно тестировать...

// С фасадом — намерение выражено одной строкой
TestDataFacade facade = new TestDataFacade(baseUrl, token);
TestContext ctx = facade.createActiveUserWithConfirmedOrder("john", "PRODUCT-42", 2);
// ctx.getUser(), ctx.getOrder() — всё готово

Запуск тестов

./gradlew :facade:test

Отчёт о результатах: facade/build/reports/tests/test/index.html