Почему ручное написание тестов — путь в никуда
Ты QA-инженер. У тебя есть Swagger-спецификация API на 200+ эндпоинтов. Тимлид говорит: «Покрытие тестами — 80% через месяц». Ты смотришь на эту спецификацию и понимаешь: писать тесты руками — это смерть. Не физическая, но карьерная. Потому что через две недели тебя ждет выгорание и очередной «срочный рефакторинг» API, который сломает половину написанных тестов.
В 2026 году так уже не работает. OpenAPI Generator давно умеет генерировать не только клиенты, но и каркасы тестов. Cursor с Claude Code превращает этот каркас в настоящие, живые тесты с реальными данными и валидацией. А swagger-coverage показывает, какие эндпоинты остались без проверок. В этом руководстве я разложу всю цепочку: от спецификации до CI-пайплайна, который сам себя проверяет.
Важный момент: мы не пишем тесты «с нуля». Мы генерируем 80% кода, а оставшиеся 20% — это логика аутентификации, генерация реалистичных payload’ов и проверка бизнес-правил. И эти 20% добивает AI.
Что нам понадобится (инструментарий 2026 года)
Прежде чем нырять в код, давай определимся с версиями. На июнь 2026 года актуальны:
- OpenAPI Generator 7.12 — стабильная версия с поддержкой OpenAPI 3.1 и новыми шаблонами для тестов (JUnit 5, Pytest, Jest).
- Cursor 0.45+ — с нативной интеграцией Claude Code 3 (без дополнительных прокси).
- Claude Code (встроен в Cursor) — модель 3.5 Sonnet или Opus, которая отлично понимает OpenAPI-спецификации.
- swagger-coverage 1.5 — инструмент, который парсит результаты тестов и рисует heatmap покрытия.
- Node.js 22 или Java 21 (для генератора, если используешь JAR).
oneOf/anyOf в схемах, что приводит к дырявым тестам.Шаг 1. Генерация тестового каркаса через OpenAPI Generator
1Установка и первый запуск
Проще всего использовать npm-пакет @openapitools/openapi-generator-cli. Он тянет за собой сам генератор.
npm install -g @openapitools/openapi-generator-cli
openapi-generator-cli version
# ожидаем: 7.12.0Теперь генерируем тесты. Допустим, у нас есть petstore.yaml. Нам нужен генератор python-pytest (если пишешь на Python) или java-junit5. Я покажу на Python, потому что он ближе QA-инженерам.
openapi-generator-cli generate -i petstore.yaml \
-g python-pytest \
-o ./generated-tests \
--additional-properties=library=urllib3,testPackage=testНа выходе получаем папку generated-tests/test/ с файлами вида test_pet_api.py. Внутри — методы с заглушками:
def test_add_pet(self):
"""Test case for add_pet"""
body = {} # TODO
response = self.api.add_pet(body)
# TODO: assert response
Заметил? Там пустой словарь, нет реальных данных, нет проверок статус-кода. И это нормально. OpenAPI Generator делает ровно то, что заложено в шаблонах — структуру. А наполнять будем дальше.
2Кастомные Mustache-шаблоны — почему они тебе нужны
Генератор использует Mustache-шаблоны. Если тебя не устраивает стандартный скелет (например, нет проверки response.status_code или не генерируется pytest.mark.parametrize), ты можешь переопределить шаблоны. Создай папку my-templates/python-pytest, скопируй туда дефолтные из репозитория генератора и меняй.
Вот фрагмент шаблона, который я докрутил, чтобы сразу вставлять примеры данных из examples спецификации:
def test_{{operationId}}(self):
"""Test case for {{operationId}}"""
{{#bodyParam}}
body = {{{vendorExtensions.x-example}}} if {{{vendorExtensions.x-example}}} else {}
{{/bodyParam}}
response = self.api.{{operationId}}({{#bodyParam}}body{{/bodyParam}})
assert response.status_code == {{#defaultResponse}}{{statusCode}}{{/defaultResponse}}{{^defaultResponse}}200{{/defaultResponse}}Затем генерируем с указанием кастомных шаблонов:
openapi-generator-cli generate -i petstore.yaml \
-g python-pytest \
-o ./generated-tests \
-t ./my-templates/python-pytestВажно: спецификация должна содержать поля example или examples, иначе шаблон не подхватит данные. Если спецификация от разработчиков без примеров — беда. Но об этом позже.
Шаг 2. Подключаем Cursor и Claude Code — превращаем болванку в настоящий тест
Сгенерированный код — это еще не тесты. Это скелет. Чтобы оживить его, нужен AI, который понимает контекст API. Открываем Cursor, делаем Ctrl+K (или Cmd+K) и вводим промпт:
У нас есть OpenAPI спецификация в файле petstore.yaml.
В папке generated-tests/test/ лежат сгенерированные тесты.
Для каждого теста:
1. Прочитай спецификацию и определи обязательные поля.
2. Сгенерируй реалистичные данные (используй faker или случайные UUID).
3. Добавь проверки статус-кода (200, 201, 404).
4. Если в ответе есть schema, добавь валидацию с помощью pydantic.
5. Учти, что некоторые эндпоинты требуют авторизации — для них передай токен из фикстуры.Claude Code (через Cursor) анализирует и спецификацию, и код, и за несколько секунд дополняет файлы. Это не магия — это tool_use: модель читает файлы, пишет правки, запускает тесты и исправляет ошибки.
Я настоятельно советую прочитать статью Schema-enforced execution с tool_use: как повысить надежность структурированных ответов Claude до 95% — она как раз про то, как заставить модель не выдумывать, а строго следовать схеме ответа. В нашем контексте это критично: если Claude неправильно поймет тип поля, тест упадет.
Но есть нюанс: Claude может нагаллюцинировать фикстуры или пропустить статус-код. Чтобы этого избежать, используй локальный 'слой истины' для Claude Code. Этот «слой» — файл CLAUDE.md в корне проекта, в котором ты описываешь правила генерации тестов: какие библиотеки использовать, как называть тестовые данные, обязательные assert’ы.
Ошибка новичка: просто скормить AI весь код и надеяться, что он сделает идеально. Не делай так. Сначала настрой CLAUDE.md и проверь, что модель читает OpenAPI-спецификацию.
Шаг 3. Валидация ответов с помощью swagger-coverage
После того, как тесты написаны, нужно понять, что мы действительно покрыли все эндпоинты и все статус-коды. swagger-coverage (версия 1.5) собирает статистику на основе выполненных HTTP-запросов. Установка:
pip install swagger-coverage
swagger-coverage generate --spec petstore.yaml --results ./test-resultsЗапускаем тесты с записью трафика (например, через pytest --coverage), и получаем HTML-отчет. Красные эндпоинты — те, что не тестируются. Можно даже настроить порог: если покрытие ниже 70% — CI падает.
Кстати, вот отличный пример интеграции AI-агентов с тестированием: Эксперимент с автономным AI-разработчиком. Там показано, как настроить цикл «генерация тестов — прогон — исправление багов». В нашем случае swagger-coverage дает сигнал, какие сценарии не покрыты, и Claude Code может сгенерировать недостающие тесты.
Шаг 4. CI/CD: всё в одном пайплайне
Финальный аккорд — собрать всю цепочку в GitHub Actions (2026 год, но ничего не изменилось). Вот пример workflow:
name: API Tests Generation & Execution
on: [push]
jobs:
generate-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm install -g @openapitools/openapi-generator-cli
- run: openapi-generator-cli generate -i spec.yaml -g python-pytest -o ./tests -t ./templates
- run: pip install -r tests/requirements.txt
- run: pytest tests/ --coverage --coverage-output=coverage.json
- run: swagger-coverage generate --spec spec.yaml --results coverage.json
- uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage.htmlЯ умышленно не включаю сюда Cursor — он нужен разработчику, а не CI. В CI мы используем уже сгенерированные и доработанные AI тесты. Но если хочешь автоматизировать доработку и в CI, используй Claude Code: полное руководство — там описана настройка Claude Code в режиме CLI для CI.
Нюансы и грабли (собери их до того, как они соберут тебя)
- Спецификация без примеров — самая частая боль. Договаривайся с разработчиками, чтобы они добавляли
exampleв схемы. Иначе AI-генерация данных будет случайной, а тесты — хрупкими. - Аутентификация — OpenAPI Generator не умеет шарить токены между тестами. Придется дописать фикстуру вручную или докинуть промпт для Claude.
- Ретейсты — если тест упал, не давай CI сразу фейлиться. Добавь
@pytest.mark.flaky(reruns=2), потому что некоторые API отвечают 500 при первом запросе. - Совместимость версий — OpenAPI Generator 7.12 требует Java 11+, но лучше использовать Java 21, чтобы избежать deprecated warning.
- Mustache-шаблоны — если меняешь шаблон, перегенерируй все тесты заново. Частичное изменение может привести к непредсказуемым результатам.
«Мы потратили неделю на написание Mustache-шаблонов, зато потом экономили по 3 дня на каждом релизе». — цитата real QA Engineer, 2026
Неочевидный совет (читай, если хочешь быть лучшим)
Большинство гайдов заканчивается победной нотой «всё работает». Но реальность сложнее. Главная проблема сгенерированных тестов — они проверяют, что API отвечает, но не проверяют смысл ответа. Например, эндпоинт POST /users возвращает 201 с пользователем, но без поля email. Статус-код пройдет, а бизнес-логика — нет.
Решение: используй schema-enforced execution для генерации assert’ов на основе JSON Schema. Claude Code может по схеме ответа создать pydantic-модель и валидировать ответ строго. Это описано в статье Schema-enforced execution с tool_use. Примени тот же подход к тестам: пусть Claude генерирует assert’ы, которые проверяют не только код, но и структуру ответа.
И последнее: не пытайся автоматизировать всё. OpenAPI Generator + Cursor + Claude Code — это мощная цепочка, но она требует человеческого глаза. Ты — DevOps, ты знаешь, где тонко. Оставь себе 10% ручных проверок на самые критичные сценарии. А всё остальное пусть генерируется.