Karate — тестирование API и UI
Karate — это фреймворк для тестирования веб-сервисов и интерфейсов. Тесты пишутся на читаемом языке сценариев, который понимает даже нетехнический аналитик, при этом за сценарием — полноценный REST-клиент, встроенные JSON-выражения и параллельный запуск.
1. Что такое Karate
- API-тесты — REST, SOAP, GraphQL — без написания Java-кода;
- UI-тесты — браузерные сценарии на том же языке;
- Load-тесты — нагрузочные прогоны через Gatling;
- тесты запускаются через JUnit и легко встраиваются в Maven/Gradle и CI.
2. Установка
Проще всего использовать автономный JAR:
wget https://github.com/karatelabs/karate/releases/latestИли положить зависимости в pom.xml:
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit5</artifactId>
<version>1.4.1</version>
<scope>test</scope>
</dependency>3. Первый сценарий
Сценарий живёт в файле с расширением .feature:
Feature: проверка API
Scenario: получаем пользователя
Given url 'https://jsonplaceholder.typicode.com/users/1'
When method get
Then status 200
And match $.name == 'Leanne Graham'Выполняется сценарий одним Java-классом:
import com.intuit.karate.junit5.Karate;
class UsersTest {
@Karate.Test
Karate testAll() {
return Karate.run("users").relativeTo(getClass());
}
}4. Шаги: Given / When / Then
| Ключевое слово | Назначение |
|---|---|
| Given | подготовить запрос: url, headers, параметры |
| When | выполнить действие: method get/post/put/delete |
| Then | проверить ответ: status, headers, body |
| And / But | добавить ещё один шаг любого типа |
Given url baseUrl + '/products'
And header Authorization = 'Bearer ' + token
And request { name: 'Чашка', price: 990 }
When method post
Then status 201
And match response.id != null5. Работа с JSON
JSON — «родной» формат Karate, обращаться к полям можно без приведения типов:
Given url baseUrl + '/users/2'
When method get
Then status 200
And match response.address.city == 'Wisokyburgh'
And match response.email == '#regex ^.+@.+\..+$'
And assert response.company.name != nullВыражения JsonPath
Then match $.id == 2
And match $..city == 'Wisokyburgh'
And match response[0].price >= 100#regex — специальный «мягкий» маркер: он проверяет формат значения, а не равенство. Полезно для id, дат и email.6. Параметризация
Для проверки множества значений используется Scenario Outline:
Scenario Outline: логин пользователя
Given url baseUrl + '/login'
And request { username: '<user>', password: '<pass>' }
When method post
Then status <code>
Examples:
| user | pass | code |
| admin | admin | 200 |
| bob | wrong | 401 |
| maria | secret | 403 |Плейсхолдеры в угловых скобках подставляются из таблицы Examples.
7. Переменные и окружение
Общие данные выносятся в файл конфигурации karate-config.js:
function fn() {
var env = karate.env || 'dev';
var config = {
baseUrl: 'https://dev.api.example.com',
token: 'test-token'
};
if (env === 'prod') {
config.baseUrl = 'https://api.example.com';
}
karate.configure('connectTimeout', 5000);
return config;
}Запуск с нужным окружением:
mvn test -Dkarate.env=prod8. Чтение данных из файлов
Given url baseUrl + '/users/bulk'
And request read('data/users.json') // из файла
When method post
Then status 200
// CSV так же легко:
* def rows = read('data/prices.csv').feature-файла.9. Отчёты и параллельный запуск
JUnit бежит по всем сценариям; по умолчанию Karate выдаёт консольный отчёт и красивые HTML-отчёты в target/karate-reports.
// параллельный запуск через maven-surefire
mvn test -Dkarate.options='--tags @smoke'Теги
@smoke
Scenario: быстрая проверка
...
@regression @slow
Scenario: тяжёлый сценарий
...10. Интеграция с CI
Karate запускается как обычный Maven-тест, поэтому встраивается в GitLab CI без дополнительных инструментов:
api-tests:
stage: test
image: maven:3.9-eclipse-temurin-17
script:
- mvn test -Dkarate.env=dev
artifacts:
paths:
- target/karate-reports11. Валидация ответов через match
Ключевой оператор Karate — match: он сравнивает ответ с шаблоном по частям, не требуя точного равенства всех полей:
* def response = { "user": { "id": 1, "name": "Ivan" } }
* match response contains { user: { id: 1 } }
* match response.user.name == "Ivan"Для схем с типами используй маркеры: #string, #number, #boolean, #array:
* def userSchema = { id: "#number", name: "#string", roles: "#array" }
* match response.user == userSchema#string вместо «2026-09-19» защитит от поломок при изменении данных.12. Авторизация: токены и refresh
Логин выносится в отдельный feature-файл и вызывается один раз через callonce, токен кладётся в заголовки через configure headers:
* configure headers = { Authorization: 'Bearer #(token)' }
* def result = callonce read('login.feature') { username: 'admin', password: 'secret' }
* def token = result.accessTokenRefresh-флоу проверяется отдельным сценарием: запрос с истёкшим токеном должен отдавать 401, а повторный логин — новый токен.
karate.properties['key'] или конфиг-файл, который не попадает в Git.13. Негативные сценарии и безопасность
Контракт API включает и проверку отказа. Покрывай неверные пейлоады, несуществующие ресурсы и битые токены:
Given url baseUrl + '/users/999'
When method get
Then status 404
Given path 'users'
And request { email: 'not-an-email' }
When method post
Then status 400- 401/403 — отсутствие или недействительность авторизации.
- 400/422 — некорректные запросы, лишние или пустые поля.
- Проверяй заголовки ответа: Content-Type, CORS, rate-limit.
14. Окружения, теги и выборочный запуск
Окружения задаются в karate-config.json, а выбор — через переменную karate.env:
{
"dev": { "baseUrl": "https://dev-api.example.com" },
"staging": { "baseUrl": "https://staging-api.example.com" }
}Пометки @smoke, @regression на сценариях позволяют запускать только нужное:
| Команда | Действие |
|---|---|
| mvn test -Dkarate.env=staging | запуск на окружении staging |
| --tags @smoke | только дымовые сценарии |
| --tags @a,@b --tags ~@slow | набор A/B без медленных |
15. Ожидание и повторные попытки
API может отвечать не мгновенно: асинхронные задачи выполняются минуты, и сразу проверять статус нельзя. Karate поддерживает опрос через retry until — удобно для пайплайнов и транзакций:
Given url baseUrl + '/jobs/' + jobId
When method get
Then status 200
And retry until response.status == 'completed'Шаг retry until повторяет последний HTTP-запрос, пока выражение не станет истинным. Параметры ожидания настраиваются глобально:
karate.configure('retry', { count: 20, interval: 3000 })count— максимальное число повторов,intervalмиллисекунд.- Обязательно проверяй таймауты наружу: 20 × 3 с = 60 с — долго для одного теста.
- Особенно полезна связка с асинхронными эвентами и вебхуками вне юрисдикции теста.
16. WebSocket и gRPC-протоколы
Не всё общение с API идёт по классическому REST: вебхуки в реальном времени и высоконагруженные сервисы используют WebSocket и gRPC. Karate умеет и то, и другое:
Given url 'ws://localhost:8080/socket'
When def socket = karate.webSocket(
And socket.send({ "type": "ping" })
And def reply = socket.receive()- WebSocket работает поверх живого соединения:
karate.webSocketшлёт и слушает сообщения без пересоздания HTTP-цикла. - gRPC тестируется бинарными протобафами: Karate генерирует клиент из
.proto. - Для асинхронных потоков дополняй проверку таймаутом — тест не должен ждать событие вечно.
retry until из прошлого урока: вошёл — слушаешь — дождался ответа.17. Смешивание с UI-тестами
Karate объединяет API и браузерные проверки: одна и та же сущность (токен, cookie) переходит из REST-вызовов в браузерные шаги.
Given driver 'https://app.example.com'
And input('#email', 'test@example.com')
And input('#password', 'secret')
And click('#login')
Then assert driver.waitUntil(() => karate.get('#dashboard') != null)Скреиншоты добавляются тегом driver.screenshot(), элементы ищутся CSS/XPATH. Полезно переиспользовать уже созданный сеанс браузера между сценариями через общий конфиг.
- Отдельный драйвер
karate-chromeподключается без Selenium. - Гибридный сценарий: API ставит данные (пользователь, заказ), UI проверяет отображение.
- Таймауты браузера
driver.timeout()настраиваются под медленные окружения.
18. Частые ошибки и советы отладки
| Симптом | Частая причина | Решение |
|---|---|---|
| Все сценарии падают одинаково | конфиг не подхватился (karate.env опечатка) | проверь karate-config.js и тег запуска |
| match не совпадает, но данные «те же» | разница типов: строка vs число | используй #number/#string или #ignore |
| Периодичность: то зелёно, то красный | зависимость от порядка данных/времени | иди в retry until или фиксируй время в запросах |
| Тест «завис» | нет таймаута в http call | karate.configure('connectTimeout', 5000) |
Логи каждого шага пишутся в target/karate-reports/karate.log — там видно фактические запросы и ответы. Начинай отладку именно с лога, а не с глазами по зелёному diff.
Xmx в surefire, иначе краши начнутся вне зависимости от кода сценариев.19. Переиспользование сценариев
Дублирование шагов — первый шаг к хрупким тестам. Karate позволяет выносить общую логику в отдельные feature и вызывать её из любого сценария.
* def token = callonce read('auth.feature')
* header Authorization = 'Bearer ' + tokencall read('helpers.feature')— повторное выполнение сценария, результат присваивается переменной.callonceвыполняет сценарий один раз и кэширует результат — идеально для получения токенов.- JS-функции и константы выносите в
karate-config.js, а не внутрь шагов.
common/ и не кладите туда assert-сценарии: они должны возвращать данные, а не проверять.20. GraphQL-тесты
Karate работает с GraphQL напрямую: запросы уходят обычным POST с JSON-телом, а ответы разбираются матчерами.
Given path 'graphql'
And request { query: '#(query)', variables: '#(vars)' }
When method post
Then status 200
And match response.data.user.name == 'Ivan'- Курируйте мутации и запросы в переменных, чтобы проверять поля и фрагменты.
- Ошибки GraphQL приходят в
errors, а не в HTTP-код — проверяйте и их. - Тестируйте интроспекцию, чтобы ловить изменения схемы до того, как они сломают фронтенд.
errors пуст: иначе «молчаливый» сбой GraphQL пройдёт незамеченным.21. Нагрузочные тесты с Karate Gatling
Те же feature-сценарии запускаются как нагрузочные через интеграцию Karate Gatling — без дублирования кода функциональных и перформанс-тестов.
val scn = karateFeature("classpath:tests.feature", "pets")
setUp(scn.inject(rampUsers(200).during(10))).protocols(karateProtocol())- Профили инъекции:
rampUsers,constantUsersPerSec,atOnceUsers. - Отчёты Gatling показывают процентили и пропускную способность по каждому шагу.
- «Тяжёлые» сценарии выносите в отдельные фичи, чтобы функциональный прогон не замедлялся.
22. Окружения и контейнеры
Надёжные тесты требуют предсказуемого окружения. Поднимайте зависимости в Docker и перехватывайте трафик там, где это нужно.
docker compose upс тестовой БД и сервисами — быстрый лаунчер для локального прогона.- Testcontainers автоматически поднимает и убирает контейнеры внутри CI-джобы.
- Прокси типа ZAP/mitmproxy перехватывает запросы Karate — удобно для правок или аудита безопасности.
docker run --rm -p 4444:4444 ghcr.io/karatelabs/karate-chromeДобавьте в CI кэширование образов и чистую сеть для контейнеров — это убирает большинство проблем «на моей машине работает».
Что дальше
Комбинируй Karate с JUnit для unit-тестов, GitLab CI для запуска и Docker для окружений. Полный список курсов — на главной странице.