TL;DR
- API тестирование проверяет backend-сервисы без UI — быстрее и надежнее E2E тестов
- Тестируй: статус-коды, тело ответа, заголовки, обработку ошибок, аутентификацию, валидацию схем, производительность
- Инструменты: Postman (ручное/обучение), REST Assured (Java), Supertest (Node.js), requests (Python)
- Автоматизируй в CI/CD — API часто меняются, ловите breaking changes рано
- Покрывай happy path и сценарии ошибок (400, 401, 404, 500)
- Валидируй схемы ответов для предотвращения дрифта контрактов между фронтом и бэком
Подходит для: Backend-разработчиков, QA-инженеров, всех, кто тестирует микросервисы Пропусти, если: Тестируешь только статические сайты или простые фронтенды
Твои фронтенд-тесты проходят. Пользователи сообщают, что приложение сломано. API изменился, и никто не протестировал контракт.
API тестирование ловит такие проблемы до того, как они дойдут до пользователей. Это быстрее UI-тестирования, надежнее и тестирует реальную бизнес-логику, от которой зависит твое приложение.
Я десятки раз ловил ломающие изменения в API контрактах — переименованное поле, измененный статус-код, пропавший заголовок пагинации. Каждый из них вызвал бы даунтайм, если бы не был пойман API тестами в CI.
Этот туториал учит API тестированию с нуля — основы HTTP, REST-конвенции, аутентификация, обработка ошибок, валидация схем и автоматизация.
Что такое API тестирование?
API (Application Programming Interface) тестирование проверяет, что твои backend-сервисы работают корректно. Вместо кликов через UI ты отправляешь HTTP-запросы напрямую к endpoints и проверяешь ответы.
Что покрывает API тестирование:
- Функциональность — делает ли endpoint то, что должен?
- Валидация данных — структурированы ли ответы правильно?
- Обработка ошибок — падает ли gracefully?
- Аутентификация — контролируется ли доступ?
- Соответствие схеме — соответствует ли ответ контракту?
- Производительность — выдерживает ли нагрузку?
Почему API тестирование важно:
- Быстрее UI-тестов — нет рендеринга браузера, миллисекунды vs секунды
- Стабильнее — нет flaky селекторов или проблем тайминга
- Раннее обнаружение — тестируй до существования фронтенда
- Лучшее покрытие — тестируй edge cases, невозможные через UI
Где API тесты в пирамиде тестирования:
/ UI тесты \ ← Медленные, дорогие, мало
/ Интеграционные \ ← API тесты живут здесь
/ Unit тесты \ ← Быстрые, дешевые, много
API тесты — золотая середина: достаточно быстрые для запуска на каждом коммите, но достаточно глубокие для поиска реальных интеграционных багов.
Основы HTTP
Перед тестированием API пойми основы HTTP.
HTTP методы
GET /users # Получить всех пользователей
GET /users/123 # Получить пользователя 123
POST /users # Создать нового пользователя
PUT /users/123 # Заменить пользователя 123
PATCH /users/123 # Обновить части пользователя 123
DELETE /users/123 # Удалить пользователя 123
| Метод | Назначение | Есть тело | Идемпотентный |
|---|---|---|---|
| GET | Чтение данных | Нет | Да |
| POST | Создание ресурса | Да | Нет |
| PUT | Замена ресурса | Да | Да |
| PATCH | Частичное обновление | Да | Нет |
| DELETE | Удаление ресурса | Опционально | Да |
Идемпотентность важна для тестирования: Вызов GET или PUT 5 раз даст тот же результат, что и один вызов. POST создает новый ресурс каждый раз. Тесты должны это учитывать — PUT тесты можно ретраить, POST тесты нуждаются в очистке.
Статус-коды
2xx Успех
├── 200 OK # Запрос успешен
├── 201 Created # Ресурс создан
├── 204 No Content # Успех, нечего возвращать
4xx Ошибки клиента
├── 400 Bad Request # Невалидный ввод
├── 401 Unauthorized # Отсутствует/невалидная авторизация
├── 403 Forbidden # Валидная авторизация, нет разрешения
├── 404 Not Found # Ресурс не существует
├── 409 Conflict # Конфликт с текущим состоянием
├── 422 Unprocessable # Валидация провалена
├── 429 Too Many Req # Rate limit превышен
5xx Ошибки сервера
├── 500 Internal Error # Баг сервера
├── 502 Bad Gateway # Ошибка upstream
├── 503 Unavailable # Сервер перегружен/обслуживание
Частая ошибка: Проверять только 200. Всегда верифицируй конкретный ожидаемый код — 200 вместо 201 означает проблему.
Тестирование с Postman
Postman — самый простой способ начать API тестирование.
Первый запрос
- Открой Postman
- Введи URL:
https://jsonplaceholder.typicode.com/posts/1 - Метод: GET
- Нажми Send
Добавление тестов
В Postman добавь JavaScript тесты во вкладке “Tests”:
// Проверка статус-кода
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
// Время ответа
pm.test("Response time is less than 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
// Валидация тела
pm.test("Has correct structure", function () {
const json = pm.response.json();
pm.expect(json).to.have.property("id");
pm.expect(json).to.have.property("title");
pm.expect(json.id).to.eql(1);
});
Коллекции, переменные и цепочки запросов
// Переменные окружения
pm.environment.set("baseUrl", "https://api.example.com");
// Цепочки: извлечь токен из логина, использовать в следующем запросе
pm.test("Save auth token", function () {
const response = pm.response.json();
pm.environment.set("token", response.token);
pm.environment.set("userId", response.user.id);
});
Запуск коллекций из CLI с Newman:
npm install -g newman
newman run collection.json -e production.json --reporters cli,html
REST API тестирование с кодом
Python с requests + pytest
import requests
import pytest
BASE_URL = "https://api.example.com"
class TestUsersAPI:
def test_get_users_returns_list(self):
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 200
assert isinstance(response.json(), list)
assert len(response.json()) > 0
def test_create_user(self):
payload = {
"name": "John Doe",
"email": "john@example.com"
}
response = requests.post(
f"{BASE_URL}/users",
json=payload,
headers={"Content-Type": "application/json"}
)
assert response.status_code == 201
data = response.json()
assert data["name"] == payload["name"]
assert "id" in data
def test_get_nonexistent_user(self):
response = requests.get(f"{BASE_URL}/users/99999")
assert response.status_code == 404
def test_create_user_invalid_email(self):
payload = {"name": "John", "email": "not-an-email"}
response = requests.post(f"{BASE_URL}/users", json=payload)
assert response.status_code == 400
JavaScript с Supertest
const request = require('supertest');
const app = require('../src/app');
describe('Users API', () => {
test('GET /users returns list of users', async () => {
const response = await request(app)
.get('/users')
.expect(200)
.expect('Content-Type', /json/);
expect(Array.isArray(response.body)).toBe(true);
});
test('POST /users creates new user', async () => {
const newUser = { name: 'John Doe', email: 'john@example.com' };
const response = await request(app)
.post('/users')
.send(newUser)
.expect(201);
expect(response.body).toMatchObject(newUser);
expect(response.body.id).toBeDefined();
});
});
Java с REST Assured
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class UsersApiTest {
@BeforeAll
public static void setup() {
RestAssured.baseURI = "https://api.example.com";
}
@Test
public void getUsersReturnsList() {
given()
.when()
.get("/users")
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("size()", greaterThan(0));
}
@Test
public void createUserReturnsCreated() {
String requestBody = """
{
"name": "John Doe",
"email": "john@example.com"
}
""";
given()
.contentType(ContentType.JSON)
.body(requestBody)
.when()
.post("/users")
.then()
.statusCode(201)
.body("name", equalTo("John Doe"))
.body("id", notNullValue());
}
}
Валидация схем ответов
Тестирование отдельных полей недостаточно. Валидируй всю структуру ответа, чтобы поймать дрифт контракта.
JSON Schema валидация с Python
from jsonschema import validate
user_schema = {
"type": "object",
"required": ["id", "name", "email", "createdAt"],
"properties": {
"id": {"type": "integer"},
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"createdAt": {"type": "string", "format": "date-time"},
"role": {"type": "string", "enum": ["admin", "user", "viewer"]}
},
"additionalProperties": False
}
def test_user_response_matches_schema():
response = requests.get(f"{BASE_URL}/users/1")
validate(instance=response.json(), schema=user_schema)
Почему валидация схемы важна: Разработчик добавляет поле, переименовывает другое или меняет тип. Точечные проверки это пропускают. Валидация схемы ловит каждое структурное изменение — это страж твоего API контракта.
Тестирование аутентификации
Bearer Token (JWT)
# Шаг 1: Логин для получения токена
login_response = requests.post(
"https://api.example.com/auth/login",
json={"email": "user@example.com", "password": "secret"}
)
token = login_response.json()["token"]
# Шаг 2: Использование токена в запросах
response = requests.get(
"https://api.example.com/protected",
headers={"Authorization": f"Bearer {token}"}
)
Тестирование сценариев авторизации
class TestAuthentication:
def test_protected_endpoint_requires_auth(self):
response = requests.get(f"{BASE_URL}/protected")
assert response.status_code == 401
def test_invalid_token_rejected(self):
response = requests.get(
f"{BASE_URL}/protected",
headers={"Authorization": "Bearer invalid_token"}
)
assert response.status_code == 401
def test_valid_token_grants_access(self):
token = get_valid_token()
response = requests.get(
f"{BASE_URL}/protected",
headers={"Authorization": f"Bearer {token}"}
)
assert response.status_code == 200
def test_insufficient_permissions(self):
viewer_token = get_token_for_role("viewer")
response = requests.delete(
f"{BASE_URL}/users/1",
headers={"Authorization": f"Bearer {viewer_token}"}
)
assert response.status_code == 403
Тестирование GraphQL
GraphQL использует один endpoint с queries и mutations. Тестирование принципиально отличается от REST.
def test_graphql_query():
query = """
query GetUser($id: ID!) {
user(id: $id) { id, name, email }
}
"""
response = requests.post(
f"{BASE_URL}/graphql",
json={"query": query, "variables": {"id": "123"}}
)
assert response.status_code == 200
data = response.json()
assert "errors" not in data
assert data["data"]["user"]["id"] == "123"
def test_graphql_invalid_query():
"""GraphQL возвращает 200 с массивом errors, не 400"""
response = requests.post(
f"{BASE_URL}/graphql",
json={"query": "{ nonExistentField }"}
)
assert response.status_code == 200
assert "errors" in response.json()
Ключевое отличие от REST: GraphQL всегда возвращает 200 для валидных HTTP запросов. Ошибки — в массиве errors внутри тела ответа.
Тестирование ошибок
Тестируй, как API обрабатывает проблемы. Здесь живет большинство багов.
class TestErrorHandling:
def test_malformed_json_returns_400(self):
response = requests.post(
f"{BASE_URL}/users",
data="not valid json",
headers={"Content-Type": "application/json"}
)
assert response.status_code == 400
def test_missing_required_field_returns_400(self):
response = requests.post(
f"{BASE_URL}/users",
json={"name": "John"} # отсутствует email
)
assert response.status_code == 400
def test_duplicate_email_returns_409(self):
requests.post(f"{BASE_URL}/users", json={
"name": "John", "email": "john@example.com"
})
response = requests.post(f"{BASE_URL}/users", json={
"name": "Jane", "email": "john@example.com"
})
assert response.status_code == 409
Тестирование Rate Limiting
Большинство API в продакшене имеют ограничения скорости. Тестируй их.
def test_rate_limiting():
response = requests.get(f"{BASE_URL}/users")
assert "X-RateLimit-Limit" in response.headers
assert "X-RateLimit-Remaining" in response.headers
def test_rate_limit_exceeded():
for _ in range(110): # Если лимит 100 запросов/мин
requests.get(f"{BASE_URL}/users")
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 429
assert "Retry-After" in response.headers
Performance тестирование
Load тестирование с k6
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 20 },
{ duration: '1m', target: 20 },
{ duration: '10s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const response = http.get('https://api.example.com/users');
check(response, {
'status is 200': (r) => r.status === 200,
'response time OK': (r) => r.timings.duration < 500,
});
sleep(1);
}
Интеграция CI/CD
name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pip install pytest requests jsonschema
- run: pytest tests/api/ -v --tb=short
- run: |
npm install -g newman
newman run collection.json -e environment.json
ИИ в API тестировании
ИИ-инструменты значительно ускоряют разработку API тестов в 2026.
Что ИИ делает хорошо:
- Генерация тест-кейсов из OpenAPI/Swagger спецификаций — вставь спеку, получи 50+ тестов
- Создание валидных и невалидных тестовых данных для граничного тестирования
- Написание boilerplate для аутентификации и CRUD операций
- Конвертация между фреймворками (скрипты Postman в pytest, REST Assured в Supertest)
Что всё ещё требует людей:
- Понимание бизнес-требований и доменных ограничений
- Проектирование стратегии тестирования (какие endpoints критичны?)
- Отладка flaky тестов из-за зависимостей данных
- Интерпретация результатов производительности
Полезный промпт:
Сгенерируй pytest тест-кейсы для POST /api/orders с телом { customerId, items: [{productId, quantity}], couponCode? }. Покрой: валидный заказ, пустой массив items, невалидный customerId, отрицательное количество, невалидный купон. Включи JSON Schema валидацию.
FAQ
Что такое API тестирование?
API тестирование проверяет, что API работает корректно, отправляя HTTP запросы и валидируя ответы. Тестирует функциональность, валидацию данных, обработку ошибок, аутентификацию и производительность. В отличие от UI тестирования, API тестирование напрямую проверяет слой бизнес-логики — типичный API тест занимает миллисекунды против секунд для браузерного теста.
Какие инструменты используются для API тестирования?
Популярные инструменты:
- Postman — GUI для ручного тестирования и автоматизации, лучший для обучения
- REST Assured — Java-библиотека с BDD-стилем
- Supertest — Node.js/JavaScript API тестирование, интеграция с Jest
- requests + pytest — Python API тестирование, максимальная гибкость
- k6 — Performance и load тестирование на JavaScript
- Newman — CLI-раннер коллекций Postman для CI/CD
- Karate — BDD-фреймворк, объединяющий API и performance тесты
В чем разница между API и unit тестированием?
Unit-тесты проверяют отдельные функции изолированно, мокая все зависимости. API-тесты проверяют полные HTTP endpoints, включая routing, middleware, аутентификацию, операции с БД и форматирование ответов. API тесты — интеграционные, проверяют работу компонентов вместе. Нужны оба: unit-тесты для логических багов, API тесты для интеграционных.
Как тестировать API с аутентификацией?
- Отправь login запрос с credentials
- Извлеки токен из ответа
- Включай токен в заголовок Authorization для последующих запросов
- Храни токен в переменной окружения для переиспользования
- Реализуй refresh токена для истекающих токенов
- Тестируй оба сценария — аутентифицированный и неаутентифицированный
- Тестируй ролевой доступ — viewer не может удалять, admin может
Чем тестирование REST API отличается от GraphQL?
REST использует множество endpoints (GET /users, POST /users) с фиксированной структурой ответа. GraphQL использует один endpoint (/graphql), где клиент запрашивает конкретные поля. Ключевые отличия: GraphQL возвращает 200 даже при ошибках (проверяй массив errors), нужно тестировать лимит глубины запросов (защита от DoS), и валидировать, что резолверы не создают N+1 запросы к БД.
Сколько API тестов нужно?
На каждый endpoint: 1 happy path тест, 2-3 негативных теста (400, 401, 404), 1 тест валидации схемы и 1 тест авторизации. Типичный CRUD ресурс (5 endpoints) нуждается в 15-20 тестах. Для API с 20 ресурсами — 300-400 тестов. Начинай с критичных для бизнеса endpoints — логин, оплата, основные данные — потом расширяй покрытие.
Официальные ресурсы
Смотрите также
- Postman Tutorial - Полное руководство по API тестированию с Postman
- REST Assured Tutorial - Java API тестирование с REST Assured
- GraphQL Testing Guide - Тестирование GraphQL API
- API Performance Testing - Load и stress тестирование API
- Contract Testing с Pact - Consumer-driven contract тестирование
- API Security Testing - OWASP API Security Top 10
- Karate API Testing - BDD-стиль автоматизации API
- Сравнение API инструментов - Postman vs REST Assured vs альтернативы
- gRPC API Testing - Тестирование gRPC сервисов
- Туториал по автоматизации - Основы автоматизации тестирования
