MLOps Path

0.1.3 · блок 0

pytest и контракты

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 блокируется, если новое поле запроса случайно сделало старый клиент несовместимым.

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

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

Открыть интерактивную версию