Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,36 @@ send_result, received = helper.send_and_receive("topic", {"data": "test"})
client.close()
```

## Design/Architecture

Проект демонстрирует не только умение писать тесты, но и способность строить общий инфраструктурный слой для разных типов интеграций. Каждый клиент решает специфичные задачи своей области и предоставляет единообразный интерфейс для тестов.

### RestClient

**Sync/Async поддержка:** Единый класс с lazy initialization для синхронного (`httpx.Client`) и асинхронного (`httpx.AsyncClient`) клиентов. Методы `get/post/put/delete` для sync, `aget/apost/aput/adelete` для async. Оба клиента создаются только при первом обращении через `@property`.

**Retry механизм:** Все HTTP методы обёрнуты декоратором `@retry()` с экспоненциальной задержкой. Настраивается через `config.settings` (количество попыток, минимальная/максимальная задержка). Автоматически обрабатывает сетевые ошибки и временные сбои.

**Хуки для логирования:** Структурированное логирование через `structlog` на уровне каждого запроса/ответа. Логируются endpoint, параметры, статус-коды. Поддержка Pydantic моделей через `_serialize()` — автоматическая конвертация в JSON.

### GraphQLClient

**Работа со схемами/queries:** Поддержка загрузки схемы через `fetch_schema_from_transport`. Выполнение запросов из файлов через `execute_from_file()` для переиспользования `.graphql` файлов. Методы `query()` и `mutate()` как семантические обёртки над `execute()`. Поддержка subscriptions через WebSocket транспорт.

**Стратегия обработки ошибок:** GraphQL специфична — ошибки могут быть в `errors` массиве при HTTP 200. Клиент логирует предупреждения, но не бросает исключения (в отличие от HTTP ошибок). Метод `raw_request()` для тестирования негативных сценариев — возвращает `httpx.Response` для проверки статус-кодов и тела ответа.

### GrpcClient

**Единый helper вокруг stubs и методов:** Абстракция над низкоуровневыми gRPC stub'ами. Методы `unary_call()`, `server_streaming()`, `client_streaming()`, `bidirectional_streaming()` принимают `stub_class` и `method_name` как параметры — не нужно создавать stub'ы вручную. Lazy initialization канала через `@property channel` с поддержкой secure/insecure соединений.

**Работа со streaming:** Все типы streaming (server, client, bidirectional) реализованы через генераторы. `server_streaming()` и `bidirectional_streaming()` возвращают `Iterator[Message]`, `client_streaming()` принимает `Iterator[Message]` как входной параметр. Единообразная обработка метаданных и таймаутов для всех типов вызовов.

### KafkaClient + KafkaTestHelper

**Решение проблемы «дождаться сообщения»:** Метод `consume_until()` с предикатом — получает сообщения до тех пор, пока условие не выполнится или не истечёт таймаут. `KafkaTestHelper.wait_for_message()` — высокоуровневая обёртка для ожидания сообщения по ключу или значению поля. Избегает проблем с порядком сообщений и race conditions.

**Стабильность тестов:** Каждый consumer создаётся с уникальным `group_id` (через фикстуры с UUID) — изоляция тестов друг от друга. `consume_one()` и `consume_batch()` создают временные consumer'ы и закрывают их автоматически — нет утечек соединений. `send_and_receive()` в helper'е — атомарная операция отправки и получения для E2E тестов. Поддержка `auto_offset_reset="earliest"` для чтения всех сообщений в топике.

## Примеры тестов

### REST тест
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies = [
# Валидация данных
"pydantic>=2.5.0",
"pydantic-settings>=2.1.0",
"email-validator>=2.0.0",

# Генерация данных
"faker>=22.0.0",
Expand Down