Modern QA2026Основы Python для QA
Join

Course12 Programming for QA

Foundations · Chapter 12

Основы Python для QA

Updated Jul 2026

Python — самый популярный язык для бэкенд/API-тестирования, валидации данных и скриптинга в мире QA. Его читаемый синтаксис, богатая стандартная библиотека и обширная экосистема библиотек для тестирования делают его выбором по умолчанию для QA-инженеров, работающих за пределами браузера.

Почему Python для QA

Сильная сторона Как помогает QA
Читаемый синтаксис Тестовый код самодокументируем; легко читается разработчиками, не знающими Python
Экосистема pytest Самый мощный тестовый фреймворк с фикстурами, параметризацией и плагинами
Библиотека requests Чистый HTTP-клиент для тестирования API
Библиотеки для данных pandas, json, csv — необходимы для валидации данных
Скорость скриптинга Быстрые скрипты для парсинга логов, очистки данных, настройки окружения
Аннотации типов + mypy Опциональная статическая типизация ловит ошибки до запуска тестов

pytest: тестовый фреймворк

pytest — стандартный тестовый фреймворк Python. Он проще, чем unittest, мощнее и используется большинством Python QA-команд.

Базовая структура теста

# test_login.py
def test_successful_login(api_client):
    response = api_client.post("/auth/login", json={
        "email": "test@example.com",
        "password": "ValidPass123!"
    })
    assert response.status_code == 200
    assert "access_token" in response.json()

def test_login_with_invalid_password(api_client):
    response = api_client.post("/auth/login", json={
        "email": "test@example.com",
        "password": "wrong"
    })
    assert response.status_code == 401
    assert "access_token" not in response.json()

Фикстуры

Фикстуры обеспечивают переиспользуемую подготовку и очистку. Они заменяют методы setup/teardown из unittest более гибким и компонуемым паттерном.

# conftest.py
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_token(base_url):
    r = requests.post(f"{base_url}/auth/login", json={
        "email": "admin@test.com", "password": "adminpass"
    })
    return r.json()["access_token"]

@pytest.fixture
def auth_headers(auth_token):
    return {"Authorization": f"Bearer {auth_token}"}

@pytest.fixture
def api_client(base_url, auth_headers):
    session = requests.Session()
    session.headers.update(auth_headers)
    session.base_url = base_url
    return session

Области видимости фикстур управляют жизненным циклом:

  • scope="function" (по умолчанию): выполняется перед/после каждого теста
  • scope="class": один раз на тестовый класс
  • scope="module": один раз на файл
  • scope="session": один раз на запуск тестов

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

Запуск одного и того же теста с разными данными:

@pytest.mark.parametrize("email,expected_status", [
    ("valid@test.com", 200),
    ("", 400),
    ("not-an-email", 422),
    ("valid@test.com; DROP TABLE users", 422),
    ("a" * 255 + "@test.com", 422),
])
def test_login_email_validation(api_client, email, expected_status):
    response = api_client.post("/auth/login", json={
        "email": email, "password": "ValidPass123!"
    })
    assert response.status_code == expected_status

Маркеры

Пометка тестов для выборочного запуска:

@pytest.mark.smoke
def test_health_check(base_url):
    assert requests.get(f"{base_url}/health").status_code == 200

@pytest.mark.slow
def test_full_checkout_flow(api_client):
    # ... lengthy test
    pass
pytest -m smoke          # Run only smoke tests
pytest -m "not slow"     # Skip slow tests

Библиотека requests

Стандартный HTTP-клиент для тестирования API на Python.

import requests

# GET with query parameters
r = requests.get("https://api.example.com/users", params={"page": 1, "limit": 10})
print(r.status_code)     # 200
print(r.json())          # parsed JSON response
print(r.headers)         # response headers
print(r.elapsed)         # time taken

# POST with JSON body
r = requests.post("https://api.example.com/users", json={
    "name": "Alice",
    "email": "alice@example.com"
})

# PUT with headers
r = requests.put("https://api.example.com/users/123",
    json={"name": "Alice Updated"},
    headers={"Authorization": "Bearer token123"}
)

# DELETE
r = requests.delete("https://api.example.com/users/123",
    headers={"Authorization": "Bearer token123"}
)
assert r.status_code == 204

Объекты сессий

Для тестов, которым необходимо сохранять состояние (cookies, заголовки) между запросами:

session = requests.Session()
session.headers.update({"Authorization": "Bearer token123"})

# All subsequent requests include the auth header
r1 = session.get("https://api.example.com/users/me")
r2 = session.get("https://api.example.com/users/me/orders")

Паттерны валидации данных

import json
from datetime import datetime

def test_user_response_structure(api_client, base_url):
    r = api_client.get(f"{base_url}/users/me")
    user = r.json()

    # Required fields exist
    required_fields = {"id", "name", "email", "created_at", "role"}
    assert required_fields.issubset(user.keys()), f"Missing: {required_fields - user.keys()}"

    # Sensitive fields absent
    assert "password" not in user
    assert "password_hash" not in user

    # Type validation
    assert isinstance(user["id"], int)
    assert isinstance(user["name"], str)
    assert len(user["name"]) > 0

    # Date format validation
    datetime.fromisoformat(user["created_at"])  # Raises if invalid

    # Enum validation
    assert user["role"] in {"admin", "editor", "viewer"}

Управление пакетами

Инструмент Лучше всего для
pip Простые проекты, быстрая установка
poetry Управление зависимостями с lock-файлами, публикация
uv Быстрая установка, современная замена pip + venv
# Create virtual environment and install dependencies
python -m venv .venv
source .venv/bin/activate
pip install pytest requests httpx

# Or with poetry
poetry init
poetry add pytest requests httpx

# Or with uv
uv init
uv add pytest requests httpx

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

Напишите файл тестов pytest, который:

  1. Использует фикстуру для аутентификации и получения токена
  2. Тестирует создание пользователя (POST)
  3. Тестирует получение созданного пользователя (GET)
  4. Тестирует, что создание с дублирующим email возвращает 409
  5. Использует parametrize для тестирования валидации email с минимум 5 входными данными
  6. Очищает созданного пользователя в teardown фикстуры

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

  • pytest — стандарт: изучите фикстуры, parametrize и маркеры
  • requests — стандартный HTTP-клиент: изучите сессии, работу с JSON и инспекцию ответов
  • Используйте conftest.py для общих фикстур между тестовыми файлами
  • Валидируйте структуру ответа (поля, типы, отсутствие чувствительных данных), а не только коды состояния
  • Используйте parametrize для data-driven тестирования вместо копирования тестовых функций