gendesign/backend/tests/services/test_dadata_client.py
bot-backend 18a2cf0d2e
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 6s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m45s
CI / backend-tests (pull_request) Successful in 14m3s
feat(etl): гео-проход auto_core_geo_v6 (#2177 остаток)
2026-07-03 06:04:32 +05:00

92 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Тесты для dadata_client.clean_address (#2177 geo-pass).
httpx.Client замокан — реальная сеть/DaData не дёргается. settings-credentials
патчатся через monkeypatch (литерала ключа нигде нет).
"""
from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
import httpx
import pytest
from app.services import dadata_client
from app.services.dadata_client import clean_address
@pytest.fixture(autouse=True)
def _creds(monkeypatch: pytest.MonkeyPatch) -> None:
"""Задаём фейковые credentials, чтобы clean_address не отваливался на guard."""
monkeypatch.setattr(dadata_client.settings, "dadata_api_token", "test-token")
monkeypatch.setattr(dadata_client.settings, "dadata_api_secret", "test-secret")
def _mock_client(response: MagicMock) -> MagicMock:
"""httpx.Client() context-manager, post() → response."""
client = MagicMock()
client.__enter__ = MagicMock(return_value=client)
client.__exit__ = MagicMock(return_value=False)
client.post.return_value = response
return client
def _resp(status: int, json_body: Any) -> MagicMock:
resp = MagicMock()
resp.status_code = status
resp.json.return_value = json_body
resp.text = ""
return resp
def test_clean_address_returns_coords() -> None:
"""Успешный ответ с geo_lat/geo_lon → (lat, lon) float-пара."""
resp = _resp(200, [{"geo_lat": "56.8389", "geo_lon": "60.6057", "qc_geo": 0}])
with patch("httpx.Client", return_value=_mock_client(resp)):
result = clean_address("г Екатеринбург, ул Малышева, 125")
assert result == (56.8389, 60.6057)
def test_clean_address_no_coords_returns_none() -> None:
"""Ответ без geo_lat/geo_lon (адрес не геокодирован) → None."""
resp = _resp(200, [{"qc_geo": 5, "result": None}])
with patch("httpx.Client", return_value=_mock_client(resp)):
assert clean_address("нераспознаваемо") is None
def test_clean_address_empty_array_returns_none() -> None:
"""Пустой массив → None."""
resp = _resp(200, [])
with patch("httpx.Client", return_value=_mock_client(resp)):
assert clean_address("г Екатеринбург, ул X, 1") is None
def test_clean_address_short_input_returns_none() -> None:
"""Короткий/пустой адрес → None без сетевого вызова."""
assert clean_address("") is None
assert clean_address("ab") is None
def test_clean_address_no_credentials_returns_none(monkeypatch: pytest.MonkeyPatch) -> None:
"""Нет credentials → graceful None (geo-pass reject'ит, не падает)."""
monkeypatch.setattr(dadata_client.settings, "dadata_api_token", None)
monkeypatch.setattr(dadata_client.settings, "dadata_api_secret", None)
assert clean_address("г Екатеринбург, ул Малышева, 125") is None
def test_clean_address_429_returns_none() -> None:
"""HTTP 429 quota → None."""
resp = _resp(429, {})
with patch("httpx.Client", return_value=_mock_client(resp)):
assert clean_address("г Екатеринбург, ул X, 1") is None
def test_clean_address_timeout_returns_none() -> None:
"""Сетевой timeout → None, не пробрасываем исключение."""
client = MagicMock()
client.__enter__ = MagicMock(return_value=client)
client.__exit__ = MagicMock(return_value=False)
client.post.side_effect = httpx.TimeoutException("timed out")
with patch("httpx.Client", return_value=client):
assert clean_address("г Екатеринбург, ул X, 1") is None