Amiga
Оглавление курса · урок 7 из 13

Модуль 2 · Автоматизация · урок 7 из 13

API-тесты и контракты

API-тесты дешевле и стабильнее e2e, а для мобильных приложений они ещё и единственная страховка от того, что бэкенд тихо поменяет формат ответа. Агенту здесь удобно: запрос и ответ — текст, вход и выход однозначны. Разберём, откуда агенту брать ожидания, как писать тесты на Playwright и что такое контрактная проверка на практике.

Источник истины

Первый вопрос до любого кода: по чему агент будет строить ожидания?

  • Спецификация API (OpenAPI или описание в документации проекта) — лучший вариант. Тесты сверяют поведение с договорённостью.
  • Требования из задачи — если спецификации нет.
  • Код контроллеров и правила валидации — удобно, но опасно. Как и в тест-дизайне, тесты по коду подтверждают то, что код делает, а не то, что должен.

Рабочий компромисс: попросить агента восстановить описание API из кода, отдать его на сверку разработчику или аналитику и только потом писать тесты по утверждённому описанию.

text
Прочитай маршруты и контроллеры плагина src/plugins/<vendor>/<plugin>
(routes.php, controllers, правила валидации). Составь описание API
в виде таблицы: метод, путь, авторизация, поля запроса с типами и
правилами, коды ответов, поля ответа. Где поведение неочевидно —
пометь «уточнить». Тесты пока не пиши.

Это описание полезно само по себе: часто его нет нигде, кроме кода.

Тесты на Playwright

Если e2e уже на Playwright, API-тесты удобно держать там же: фикстура request даёт HTTP-клиент с тем же baseURL.

typescript · tests/api/leads.spec.ts
import { test, expect } from '@playwright/test';

test.describe('POST /api/leads', () => {
  test('отклоняет заявку без email и телефона', async ({ request }) => {
    const res = await request.post('/api/leads', {
      data: { name: 'QA', email: '', phone: '' },
    });

    expect(res.status()).toBe(422);
    const body = await res.json();
    expect(body.errors).toHaveProperty('email');
  });

  test('не принимает GET', async ({ request }) => {
    const res = await request.get('/api/leads');
    expect(res.status()).toBe(405);
  });
});

Код 422 с полем errors — стандартный ответ валидации Laravel; если ваш API отвечает иначе, это и должно быть в описании API, а не в догадках агента.

Матрица негативных сценариев

Попросите агента пройти по каждому эндпоинту с одним и тем же списком измерений:

  • обязательные поля отсутствуют, пустые, null, неверного типа;
  • границы длины и формата, юникод, очень большие тела запроса;
  • неверный метод, неверный Content-Type, битый JSON;
  • без авторизации, с чужим токеном, с просроченным токеном;
  • доступ к чужому ресурсу по подмене идентификатора (/api/orders/124 вместо своего 123);
  • повторная отправка того же запроса — не создаёт ли дубль.

Пункт про чужой ресурс особенно важен: ошибки контроля доступа агент сам ищет редко, а в API для мобильных приложений они встречаются часто.

Контракты: форма ответа

Мобильное приложение в сторе нельзя обновить мгновенно. Если бэкенд переименовал поле или сделал его необязательным, старые версии приложения сломаются у пользователей. Контрактная проверка ловит это до релиза: тест сверяет не конкретные значения, а форму ответа.

Простой вариант — схема ответа в тесте. Ниже пример с библиотекой zod; подойдёт любая библиотека схем, которая уже есть в проекте.

typescript · tests/api/cases.contract.spec.ts
import { test, expect } from '@playwright/test';
import { z } from 'zod';

const CaseItem = z.object({
  id: z.number().int(),
  slug: z.string().min(1),
  title: z.string().min(1),
  cover: z.string().url().nullable(),
  tags: z.array(z.string()),
});

test('GET /api/cases соответствует контракту мобильного клиента', async ({ request }) => {
  const res = await request.get('/api/cases?limit=5');
  expect(res.status()).toBe(200);

  const parsed = z.array(CaseItem).safeParse(await res.json());
  expect(parsed.success, JSON.stringify(parsed.error?.issues, null, 2)).toBe(true);
});

Сообщение во втором аргументе expect выводит список расхождений — по нему сразу видно, какое поле поменялось. Попросите агента собрать такие схемы для всех эндпоинтов, которые использует мобильное приложение, причём по модели данных в коде приложения, а не по ответу сервера. Тогда тест проверяет ожидания клиента, а не фиксирует текущее поведение бэкенда.

В зрелом варианте это контракты, которые ведёт сторона-потребитель (consumer-driven contracts), со своими инструментами. Начинать можно со схем в тестах — это уже закрывает основной риск.

Чего агенту не разрешать

  • Ходить в боевой API с запросами на запись. Только локальный стенд или тестовое окружение. Запишите это в AGENTS.md и не включайте агенту сеть шире нужного.
  • Сравнивать ответ целиком со снимком. В ответе есть даты, идентификаторы, порядок — такой тест падает на каждом прогоне, и агент начнёт «чинить» его, ослабляя проверки.
  • Ограничиваться кодом ответа. Тест, который проверяет только 200, пройдёт и тогда, когда в теле пусто.
  • Дёргать настоящие внешние сервисы — CRM, почту, платёжный шлюз. В тестах они подменяются.

Ревью API-тестов

Перед тем как принять работу, задайте агенту контрольный вопрос — его стоит повторять для любого набора тестов:

text
Для каждого теста в tests/api/leads.spec.ts назови одно конкретное
изменение в коде API, при котором тест упадёт. Если такого изменения
не придумать — тест бесполезен, пометь его.

Это упрощённая ручная версия мутационного тестирования, о котором подробно — в уроке «Как проверять тесты, написанные агентом».

Попробуйте сами

10–15 мин на рабочем месте
  1. Попросите агента восстановить описание API одного модуля из кода и отметить места «уточнить». Покажите таблицу разработчику.
  2. Напишите вместе с агентом три негативных теста по матрице из урока, включая доступ к чужому ресурсу.
  3. Если у вас есть мобильное приложение, сделайте схему ответа для одного эндпоинта по модели данных в коде клиента и прогоните тест.

Коротко

  • Ожидания — из спецификации или утверждённого описания API, а не напрямую из кода контроллеров.
  • Фикстура request в Playwright позволяет держать API-тесты рядом с e2e.
  • Негативная матрица одинакова для всех эндпоинтов; доступ к чужому ресурсу проверяйте всегда.
  • Контрактная проверка формы ответа защищает мобильные клиенты от молчаливых изменений бэкенда.
  • Только тестовые окружения, никаких снимков ответа целиком и проверок одного лишь статуса.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX