Modern QA2026Newman и pytest для автоматизации API
Join

Course14 API Testing Fundamentals

Foundations · Chapter 14

Newman и pytest для автоматизации API

Updated Jul 2026

Postman отлично подходит для исследования. Для интеграции с CI/CD и масштабируемых тестовых наборов нужны инструменты командной строки: Newman для запуска коллекций Postman и pytest с requests для полного программного контроля.

Newman: коллекции Postman в CI

Newman запускает коллекции Postman из командной строки, что делает их подходящими для CI-пайплайнов.

Базовое использование

# Run a collection with an environment
newman run collection.json --environment staging.json --reporters cli,junit

# Run with specific folder
newman run collection.json --folder "Auth" --environment staging.json

# Run with data file (data-driven testing)
newman run collection.json --iteration-data test_data.csv --reporters cli,htmlextra

# Set environment variables from command line
newman run collection.json -e staging.json --env-var "auth_token=abc123"

Newman в GitHub Actions

jobs:
  api-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm install -g newman newman-reporter-htmlextra
      - run: |
          newman run tests/collection.json \
            --environment tests/staging.json \
            --reporters cli,junit,htmlextra \
            --reporter-junit-export results.xml \
            --reporter-htmlextra-export report.html
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: api-test-report
          path: |
            results.xml
            report.html

pytest + requests: полный контроль

Для продакшен-наборов API-тестов pytest с библиотекой requests обеспечивает гибкость, поддерживаемость и мощь, которых не хватает Newman.

Структура проекта

tests/
  api/
    conftest.py           # Shared fixtures
    test_auth.py          # Authentication tests
    test_users.py         # User CRUD tests
    test_orders.py        # Order tests
    test_error_handling.py
  data/
    test_users.csv        # Test data files
  pytest.ini              # Configuration

Общие фикстуры (conftest.py)

import os
import pytest
import requests

@pytest.fixture(scope="session")
def base_url():
    return os.environ.get("API_BASE_URL", "http://localhost:3000/api/v1")

@pytest.fixture(scope="session")
def auth_headers(base_url):
    """Authenticate once per test session."""
    r = requests.post(f"{base_url}/auth/login", json={
        "email": "test@example.com",
        "password": "testpass123"
    })
    assert r.status_code == 200, f"Auth failed: {r.text}"
    token = r.json()["access_token"]
    return {"Authorization": f"Bearer {token}"}

@pytest.fixture
def api(base_url, auth_headers):
    """Pre-configured API session."""
    session = requests.Session()
    session.headers.update(auth_headers)
    session.headers.update({"Content-Type": "application/json"})

    # Store base_url on session for convenience
    session._base_url = base_url
    original_request = session.request

    def patched_request(method, url, **kwargs):
        if url.startswith("/"):
            url = f"{base_url}{url}"
        return original_request(method, url, **kwargs)

    session.request = patched_request
    return session

@pytest.fixture
def create_user(api):
    """Factory fixture for creating test users with cleanup."""
    created_ids = []

    def _create(name="Test User", email=None, role="viewer"):
        import uuid
        email = email or f"test-{uuid.uuid4().hex[:8]}@test.com"
        r = api.post("/users", json={"name": name, "email": email, "role": role})
        assert r.status_code == 201
        user = r.json()
        created_ids.append(user["id"])
        return user

    yield _create

    # Cleanup: delete all created users
    for uid in created_ids:
        api.delete(f"/users/{uid}")

Примеры тестов

# test_users.py

def test_create_user(api, create_user):
    user = create_user(name="Alice", role="admin")
    assert user["name"] == "Alice"
    assert user["role"] == "admin"
    assert "id" in user

def test_get_user(api, create_user):
    user = create_user(name="Bob")
    r = api.get(f"/users/{user['id']}")
    assert r.status_code == 200
    assert r.json()["name"] == "Bob"

def test_update_user(api, create_user):
    user = create_user(name="Original")
    r = api.put(f"/users/{user['id']}", json={
        "name": "Updated",
        "email": user["email"],
        "role": user["role"]
    })
    assert r.status_code == 200
    assert r.json()["name"] == "Updated"

def test_delete_user(api, create_user):
    user = create_user()
    r = api.delete(f"/users/{user['id']}")
    assert r.status_code == 204
    # Verify deletion
    r = api.get(f"/users/{user['id']}")
    assert r.status_code == 404

@pytest.mark.parametrize("email,expected", [
    ("valid@test.com", 201),
    ("", 400),
    ("not-an-email", 422),
    ("a" * 300 + "@test.com", 422),
])
def test_create_user_email_validation(api, email, expected):
    r = api.post("/users", json={"name": "Test", "email": email, "role": "viewer"})
    assert r.status_code == expected

Newman vs pytest: когда что использовать

Аспект Newman pytest + requests
Кривая обучения Низкая (если используете Postman) Средняя (требуется Python)
Гибкость Ограничена скриптингом Postman Полная экосистема Python
Тестирование на основе данных CSV/JSON файлы данных pytest parametrize, фикстуры
Поддержка при масштабировании Коллекции становятся неуправляемыми Стандартный код с модулями и импортами
Отладка Консоль Postman Python debugger, логирование
Переиспользуемые утилиты Ограниченные Полный Python: пользовательские утверждения, хелперы, библиотеки
Контроль версий JSON-экспорт (сложно сравнивать) Python-файлы (легко сравнивать и ревьюить)
Командная работа Рабочие области Postman Git (стандартный код-ревью)

Гибридный подход

Многие команды используют оба инструмента:

  • Postman + Newman для smoke-тестов и быстрых проверок эндпоинтов
  • pytest для комплексных тестовых наборов со сложной логикой, подготовкой данных и очисткой

Запуск тестов в CI

# Run all API tests
API_BASE_URL=https://api.staging.example.com pytest tests/api/ -v --junitxml=results.xml

# Run only smoke tests
API_BASE_URL=https://api.staging.example.com pytest tests/api/ -m smoke -v

# Run with parallel execution
API_BASE_URL=https://api.staging.example.com pytest tests/api/ -n 4 -v

# Run against production (read-only tests only)
API_BASE_URL=https://api.example.com pytest tests/api/ -m "readonly" -v

Практическое упражнение

  1. Создайте проект pytest с conftest.py, содержащим фикстуры base_url, auth и API-сессии
  2. Напишите CRUD-тесты для ресурса (создание, чтение, обновление, удаление)
  3. Добавьте параметризованные тесты валидации для хотя бы одного эндпоинта
  4. Добавьте фабричную фикстуру, создающую тестовые данные и очищающую их после теста
  5. Запустите набор тестов против локального или публичного API

Ключевые выводы

  • Newman запускает коллекции Postman в CI — быстро настраивается, ограничен в гибкости
  • pytest + requests обеспечивает полный программный контроль для продакшен-тестовых наборов
  • Используйте фикстуры для общей настройки: авторизация, API-сессии, фабрики тестовых данных
  • Фабричные фикстуры с очисткой предотвращают накопление тестовых данных
  • Параметризуйте для тестирования на основе данных вместо дублирования тестовых функций
  • Гибридный подход (Postman для исследования, pytest для CI) хорошо работает для многих команд