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 инженеров, всех, кто тестирует микросервисы Пропусти, если: Тестируешь только статические сайты или простые фронтенды Время чтения: 18 минут

Твои фронтенд-тесты проходят. Пользователи сообщают, что приложение сломано. API изменился, и никто не протестировал контракт.

API тестирование ловит такие проблемы до того, как они дойдут до пользователей. Это быстрее UI-тестирования, надежнее и тестирует реальную бизнес-логику, от которой зависит твое приложение.

Этот туториал учит API тестированию с нуля — основы HTTP, REST конвенции, аутентификация, обработка ошибок и автоматизация с популярными инструментами.

Что такое API тестирование?

API (Application Programming Interface) тестирование проверяет, что твои backend-сервисы работают корректно. Вместо кликов через UI ты отправляешь HTTP-запросы напрямую к endpoints и проверяешь ответы.

Что покрывает API тестирование:

  • Функциональность — делает ли endpoint то, что должен?
  • Валидация данных — структурированы ли ответы правильно?
  • Обработка ошибок — падает ли gracefully?
  • Аутентификация — контролируется ли доступ?
  • Производительность — выдерживает ли нагрузку?

Почему API тестирование важно:

  • Быстрее UI-тестов — нет рендеринга браузера, миллисекунды vs секунды
  • Стабильнее — нет flaky селекторов или проблем тайминга
  • Раньше обратная связь — тестируй до существования фронтенда
  • Лучшее покрытие — тестируй edge cases, невозможные через UI

Основы 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Удаление ресурсаОпциональноДа

Статус-коды

2xx Успех
├── 200 OK              # Запрос успешен
├── 201 Created         # Ресурс создан
├── 204 No Content      # Успех, нечего возвращать

4xx Ошибки клиента
├── 400 Bad Request     # Невалидный ввод
├── 401 Unauthorized    # Отсутствует/невалидная авторизация
├── 403 Forbidden       # Валидная авторизация, нет разрешения
├── 404 Not Found       # Ресурс не существует
├── 409 Conflict        # Конфликт с текущим состоянием
├── 422 Unprocessable   # Валидация провалена

5xx Ошибки сервера
├── 500 Internal Error  # Баг сервера
├── 502 Bad Gateway     # Ошибка upstream
├── 503 Unavailable     # Сервер перегружен/обслуживание

Тестирование с Postman

Postman — самый простой способ начать API тестирование.

Первый запрос

  1. Открой Postman
  2. Введи URL: https://jsonplaceholder.typicode.com/posts/1
  3. Метод: GET
  4. Нажми 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.test("Content-Type is JSON", function () {
    pm.expect(pm.response.headers.get("Content-Type"))
      .to.include("application/json");
});

REST API тестирование с кодом

Python с requests

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)

    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);
    }

    @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());
    }
}

Тестирование аутентификации

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

Тестирование GraphQL

GraphQL использует один endpoint с queries и mutations.

Тестирование Query

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"

Тестирование ошибок

Тестируй, как 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

Performance тестирование

Load тестирование с k6

// k6 script: load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 20 },   // Ramp до 20 пользователей
    { duration: '1m', target: 20 },    // Держим 20 пользователей
    { duration: '10s', target: 0 },    // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],  // 95% под 500ms
    http_req_failed: ['rate<0.01'],    // Меньше 1% ошибок
  },
};

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);
}

AI-Assisted API тестирование

AI инструменты могут ускорить разработку API тестов.

Что AI делает хорошо:

  • Генерация тест-кейсов из OpenAPI/Swagger спецификаций
  • Создание валидных и невалидных тестовых данных
  • Написание boilerplate для частых паттернов
  • Предложение edge cases для тестирования

Что всё ещё требует людей:

  • Понимание бизнес-требований
  • Проектирование стратегии тестирования
  • Отладка flaky тестов
  • Интерпретация результатов производительности

FAQ

Что такое API тестирование?

API тестирование проверяет, что API работает корректно, отправляя HTTP запросы и валидируя ответы. Тестирует функциональность, валидацию данных, обработку ошибок, аутентификацию и производительность. В отличие от UI тестирования, API тестирование напрямую проверяет слой бизнес-логики.

Какие инструменты используются для API тестирования?

Популярные инструменты:

  • Postman — GUI инструмент для ручного тестирования и автоматизации
  • REST Assured — Java библиотека для API тестирования
  • Supertest — Node.js/JavaScript API тестирование
  • requests + pytest — Python API тестирование
  • k6 — Performance и load тестирование

В чем разница между API и unit тестированием?

Unit-тесты проверяют отдельные функции изолированно, мокая все зависимости. API-тесты проверяют полные HTTP endpoints, включая routing, middleware, аутентификацию, операции с БД и форматирование ответов. API-тесты — интеграционные тесты, которые проверяют работу компонентов вместе.

Как тестировать API с аутентификацией?

  1. Отправь login запрос с credentials
  2. Извлеки токен из ответа
  3. Включай токен в заголовок Authorization для последующих запросов
  4. Храни токен в переменной окружения для переиспользования
  5. Реализуй refresh токена для истекающих токенов

Официальные ресурсы

Смотрите также