00 · Foundation и диагностика0.1 · Вход и инженерный фундамент0.1.3средний

pytest и контракты

Зачем это нужно

Модель может выдавать правильный score, но сервис всё равно сломается из-за изменённого JSON-поля, status code или формата ошибки. Тесты проверяют не только алгоритм, но и обещания сервиса его потребителям.

Основные идеи

pytest ищет тесты, запускает их изолированно и показывает короткий отчёт о сбоях. Один тест отвечает на один понятный вопрос.

Fixtures готовят общие данные и зависимости: тестовый клиент, маленькую модель, настройки. Они уменьшают копирование и не должны скрывать важный контекст.

Contract test HTTP API фиксирует внешний договор:

Сценарий Ожидание
валидный запрос 200, предсказание нужного типа
нет обязательного поля 422, понятная ошибка валидации
модель недоступна контролируемый 503, не traceback

Контракт — это не проверка внутренней реализации. После рефакторинга API-тест должен оставаться зелёным, если внешний договор не изменился.

Как это выглядит на практике

` def test_predict_returns_probability(client): response = client.post("/predict", json={"age": 35, "income": 120_000})

assert response.status_code == 200
body = response.json()
assert 0 <= body["probability"] <= 1

def test_predict_rejects_missing_feature(client): response = client.post("/predict", json={"age": 35})

assert response.status_code == 422

`

В CI запускается pytest: merge блокируется, если новое поле запроса случайно сделало старый клиент несовместимым.

Что сделать после занятия

  • Установите pytest как dev-зависимость и выполните pytest.

  • Сделайте fixture с тестовым HTTP-клиентом.

  • Напишите тесты на успешный и невалидный запрос к /predict.

Официальные материалы