Перейти к содержанию

Тестирование с FakeTransport

avito.testing предоставляет FakeTransport — детерминированный fake transport для тестов. Он не выполняет реальных HTTP-запросов и позволяет проверять поведение consumer-кода через публичный SDK API.

Создание клиента поверх FakeTransport

FakeTransport.as_client() создаёт полностью инициализированный AvitoClient без реального HTTP. Используйте его в тестах вместо AvitoClient.from_env().

from avito.testing import FakeTransport

fake = FakeTransport()
fake.add_json(
    "GET",
    "/core/v1/accounts/self",
    {"id": 7, "name": "Тест", "email": "test@example.com", "phone": "+7999"},
)

with fake.as_client(user_id=7) as avito:
    profile = avito.account().get_self()

print(profile.user_id)
print(profile.name)

Скриптование последовательности ответов

route_sequence задаёт несколько ответов для одного маршрута. Ответы расходуются по одному. Последний ответ в очереди переиспользуется.

from avito.testing import FakeTransport, json_response, route_sequence

fake = FakeTransport()
fake.add(
    "GET",
    "/core/v1/accounts/self",
    *route_sequence(
        json_response({"id": 7, "name": "Тест", "email": "a@b.com", "phone": "+7"}),
        json_response({"id": 7, "name": "Обновлён", "email": "a@b.com", "phone": "+7"}),
    ),
)

with fake.as_client(user_id=7) as avito:
    first = avito.account().get_self()
    second = avito.account().get_self()

print(first.name)
print(second.name)

Инспекция вызовов

fake.requests содержит список RecordedRequest со всеми выполненными HTTP-запросами. Используйте его для проверки payload, метода и пути.

from avito.testing import FakeTransport

fake = FakeTransport()
fake.add_json(
    "GET",
    "/core/v1/accounts/self",
    {"id": 7, "name": "Тест", "email": "t@e.com", "phone": "+7"},
)

with fake.as_client(user_id=7) as avito:
    avito.account().get_self()

assert len(fake.requests) == 1
req = fake.requests[0]
print(req.method)
print(req.path)

Симуляция ошибок transport

FakeResponse позволяет вернуть любой HTTP-статус для проверки обработки ошибок.

from avito.core.exceptions import AuthenticationError
from avito.testing import FakeResponse, FakeTransport

fake = FakeTransport()
fake.add(
    "GET",
    "/core/v1/accounts/self",
    FakeResponse(401, json={"error": "unauthorized", "error_description": "token expired"}),
)

with fake.as_client(user_id=7) as avito:
    try:
        avito.account().get_self()
    except AuthenticationError as exc:
        print(exc.status_code)
        print(exc.operation)

Симуляция rate limit с Retry-After

Для проверки retry-поведения задайте ответ 429 с заголовком Retry-After. SDK учитывает заголовок при расчёте задержки повтора.

from avito.core.exceptions import RateLimitError
from avito.core.retries import RetryPolicy
from avito.testing import FakeResponse, FakeTransport, json_response, route_sequence

fake = FakeTransport()
fake.add(
    "GET",
    "/core/v1/accounts/self",
    *route_sequence(
        FakeResponse(429, json={"error": "too_many_requests"}, headers={"Retry-After": "1"}),
        json_response({"id": 7, "name": "Тест", "email": "t@e.com", "phone": "+7"}),
    ),
)

policy = RetryPolicy(max_attempts=2, max_rate_limit_wait_seconds=2.0)
with fake.as_client(user_id=7, retry_policy=policy) as avito:
    profile = avito.account().get_self()

print(profile.user_id)
print(len(fake.requests))

Полный публичный контракт avito.testing описан в reference по тестированию. Стратегия тестирования SDK разобрана в explanations.