automationtools

REST API тестирование на Python: pytest + requests за час

Если ты ручной тестировщик и хочешь начать автоматизировать — REST API через Python — самый низкий порог входа. Никакого UI, никаких флэйков, никакого Selenium-сетапа. Только HTTP, JSON и assert’ы. Гайд за час.

Установка

pip install pytest requests

Готово. Никаких драйверов, никаких браузеров.

Первый тест

import requests

def test_get_user():
    response = requests.get('https://api.example.com/users/1')
    
    assert response.status_code == 200
    
    user = response.json()
    assert user['id'] == 1
    assert 'email' in user

Запуск: pytest test_users.py -v.

Структура реальных тестов

import pytest
import requests

BASE_URL = 'https://api.example.com'

@pytest.fixture
def auth_headers():
    response = requests.post(f'{BASE_URL}/auth/login', json={
        'email': '[email protected]',
        'password': 'pass123'
    })
    token = response.json()['token']
    return {'Authorization': f'Bearer {token}'}

def test_create_user(auth_headers):
    response = requests.post(
        f'{BASE_URL}/users',
        headers=auth_headers,
        json={'name': 'New User', 'email': '[email protected]'}
    )
    assert response.status_code == 201
    assert response.json()['name'] == 'New User'

def test_user_not_found(auth_headers):
    response = requests.get(f'{BASE_URL}/users/999999', headers=auth_headers)
    assert response.status_code == 404

Fixture auth_headers логинится один раз и передаётся в каждый тест — DRY-принцип в action.

Что тестировать

Status codes: 200, 201, 400, 401, 403, 404, 500 — каждый соответствует ожиданию. — JSON Schema: структура ответа стабильна. Используй jsonschema для валидации. — Headers: Content-Type, Cache-Control, security headers (X-Frame-Options, etc.). — Идемпотентность: GET, PUT, DELETE — повторный вызов с теми же параметрами даёт тот же результат. — Boundary: пустой body, максимальный размер, спецсимволы, unicode, очень длинные строки. — Авторизация: без токена → 401. С чужим токеном → 403.

Параметризация

Один тест — много инпутов:

@pytest.mark.parametrize('email,expected_status', [
    ('[email protected]', 200),
    ('invalid-email', 400),
    ('', 400),
    ('a' * 1000 + '@example.com', 413),  # too long
    ("user'; DROP [email protected]", 400),  # SQL injection attempt
])
def test_login_email_validation(email, expected_status):
    response = requests.post(f'{BASE_URL}/auth/login', json={'email': email, 'password': 'x'})
    assert response.status_code == expected_status

5 тестов в одной функции.

Контракт-тесты

API-команда обновила endpoint? Сравнить ответ с зафиксированным контрактом:

import jsonschema

USER_SCHEMA = {
    'type': 'object',
    'required': ['id', 'email', 'created_at'],
    'properties': {
        'id': {'type': 'integer'},
        'email': {'type': 'string', 'format': 'email'},
        'created_at': {'type': 'string', 'format': 'date-time'},
    }
}

def test_user_contract():
    response = requests.get(f'{BASE_URL}/users/1')
    jsonschema.validate(response.json(), USER_SCHEMA)

Бэкенд убрал created_at или поменял тип id → тест красный.

Полезные тулзы вокруг

httpx (вместо requests) — поддерживает async, отлично для нагрузочных тестов. — VCR.py — записывает HTTP-ответы один раз, потом playback’ит. Тесты не зависят от внешнего сервера. — Allure — красивые HTML-отчёты. — Postman — для exploration, дальше переноси в pytest.

С чего начать

✅ Возьми один endpoint из своего продукта, напиши 3 теста — positive, negative, boundary.

✅ Заведи tests/api/ директорию в репо разработки, прикрути pytest в CI.

✅ Подключи pytest --cov для отчёта о coverage.

Через неделю у тебя будет 30 API-тестов, гоняющихся на каждый PR. Через месяц — full smoke suite. Это самый быстрый путь от мануального QA к автоматизатору.

Подробнее: requests docs, pytest docs.