Зачем это нужно
Модель может выдавать правильный 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.