中文翻译暂不可用,显示俄语原文。

Написать тесты для меж-агентской коммуникации

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Написать тесты для меж-агентской коммуникации

1. Цель задачи

Протестировать протокол обмена сообщениями между AI-агентами в многомодульной системе. Создать мокированную шину сообщений (mock message bus), которая эмулирует реальный брокер (например, RabbitMQ или Kafka), и написать набор тестов, проверяющих корректность формата, маршрутизации, обработки ошибок и восстановления после сбоев. Достичь покрытия кода модуля коммуникации не менее 95% (branch coverage + line coverage).

Ключевой результат Набор автоматизированных тестов (Python + pytest), которые запускаются единой командой и подтверждают, что протокол меж-агентской коммуникации работает корректно во всех штатных и аварийных сценариях.

2. Исходные данные

Перед началом необходимо иметь или создать:

Что нужноОткуда взять
Описание протокола сообщений (формат, типы, маршруты, обязательные поля)Прилагается к задаче (см. ниже)
Агенты-заглушки (sender / receiver), реализующие базовый интерфейсНаписать самостоятельно или взять готовый шаблон
Исходный код модуля agent_comm (классы MessageBus, Agent, Message)Предоставлен репозиторием задания (входной код для тестирования)
Инструмент для измерения покрытияУстановить pytest-cov или coverage.py

Если нет реального модуля agent_comm — симулируем:

  1. Создать пакет agent_comm со следующей структурой:
    agent_comm/
    ├── __init__.py
    ├── message.py       # класс Message (dict с полями: id, sender, receiver, type, payload, timestamp)
    ├── bus.py           # класс MessageBus (регистрация агентов, отправка, подписка)
    ├── agent.py         # абстрактный Agent (методы on_message, send)
    └── exceptions.py    # кастомные исключения (MessageFormatError, TimeoutError, BusFull)
    
  2. Реализовать MessageBus на основе очередей asyncio.Queue или обычных списков (для синхронного варианта).
  3. Включить хотя бы один реальный сценарий: агент отправляет сообщение другому, агент подписывается на топик, шина проверяет обязательные поля.
  4. Предоставить этот код исполнителю задачи.

Дополнительные ресурсы

  • Протокол: JSON-сообщение с полями id (UUID), sender, receiver, type (строка), payload (словарь), timestamp (ISO 8601). Валидация через Pydantic-модели.
  • Шина поддерживает: send (точка-точка), publish (топик), subscribe, unsubscribe, гарантии exactly-once (имитация).

3. Технологический стек

КомпонентИнструментыНазначение
Язык программированияPython 3.11+Реализация агентов и шины
Тестированиеpytest 8.x, pytest-asyncioЗапуск unit- и integration-тестов
Мокиunittest.mock / pytest-mockЗамена внешних зависимостей (брокер, логгер)
Покрытиеpytest-cov (coverage.py)Измерение line + branch coverage
Валидация сообщенийpydantic v2Проверка формата сообщений
АсинхронностьasyncioЭмуляция реальной асинхронной шины
Линтер/форматтерruffПоддержание стандарта кода

4. Этапы выполнения

Этап 1: Изучение спецификации и подготовка фикстур (оценка 30 мин)

Действия

  1. Прочитать описание протокола и интерфейс классов в модуле agent_comm.
  2. Определить, какие тесты необходимы (см. критерии приемки).
  3. Создать файл tests/test_message_bus.py и фикстуру message_bus:
    @pytest.fixture
    def message_bus():
        return MessageBus()
    
  4. Создать фикстуру sample_message для генерации тестового сообщения.
  5. Настроить pyproject.toml для включения branch coverage:
    [tool.coverage.run]
    branch = true
    source = ["agent_comm"]
    
    [tool.coverage.report]
    show_missing = true
    

Ожидаемый результат этапа Готовый скелет тестового файла, фикстуры, корректная конфигурация coverage.

Этап 2: Написание тестов для базовой отправки/получения (оценка 1.5 ч)

Действия

  1. Написать тест test_send_message:
    • регистрируем агента-получателя receiver_agent
    • отправляем сообщение через message_bus.send(receiver_id, msg)
    • проверяем, что получатель вызвал on_message с этим сообщением.
  2. Написать тест test_publish_subscribe:
    • два агента подписываются на один топик
    • публикуем сообщение через message_bus.publish(topic, msg)
    • оба агента должны получить сообщение.
  3. Написать тест test_message_validation:
    • пытаемся отправить сообщение без обязательного поля type
    • ожидаем MessageFormatError (или другое исключение).
  4. Написать тест test_unsubscribe:
    • подписываем агента, затем отписываем, публикуем — агент не должен получить сообщение.
  5. Написать тест test_concurrent_send (если шина async):
    • создаём несколько агентов, отправляем одновременно, проверяем, что все сообщения доставлены без потерь.
  6. Для каждого теста использовать pytest-asyncio (если шина async) или обычный pytest.

Ожидаемый результат этапа Все основные сценарии отправки/получения покрыты тестами, уровень line coverage > 70%.

Этап 3: Тестирование обработки ошибок и граничных случаев (оценка 1 ч)

Действия

  1. Написать тест test_send_to_nonexistent_agent:
    • отправка на несуществующий ID — ожидать исключение AgentNotFoundError.
  2. Написать тест test_bus_full_capacity:
    • шина с ограничением на количество непрочитанных сообщений (например, 10)
    • заполнить очередь сверх лимита — ожидать BusFullError.
  3. Написать тест test_invalid_message_format:
    • передать не JSON-сериализуемый payload — ожидать MessageFormatError.
  4. Написать тест test_duplicate_message_id:
    • шина не должна принимать сообщение с дублирующимся id (если есть политика idempotency).
  5. Написать тест test_timeout:
    • если получатель не обработал сообщение за установленный таймаут, шина возвращает ошибку или повторяет попытку (зависит от реализации).
  6. Написать тест test_shutdown_cleanup:
    • при вызове message_bus.stop() все незавершённые сообщения корректно завершаются (проверить отсутствие утечек задач).

Ожидаемый результат этапа Coverage branch близок к 100% в модулях bus, exceptions, message (не менее 90%).

Этап 4: Интеграционное тестирование с мок-брокером (оценка 1 ч)

Действия

  1. Если модуль agent_comm использует внешний брокер (RabbitMQ/Kafka), замокать его с помощью unittest.mock.patch:
    @patch('agent_comm.bus.RabbitMQConnection')
    def test_broker_connection_recovery(mock_connection):
        mock_connection.side_effect = ConnectionError()
        bus = MessageBus()
        # должно сработать повторное подключение
        bus.send(...)
    
    Если внешнего брокера нет, пропустить этот этап (мок-шина уже тестируется).
  2. Создать тест, проверяющий логирование (логгеры мокаются).
  3. Написать тест на долгое выполнение (stress test с 1000 сообщений) — с таймаутом, чтобы не нарушать CI.
  4. Проверить, что при ошибке сериализации сообщение не отправляется, а возвращается корректная ошибка.

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

Этап 5: Измерение покрытия и достижение 95% (оценка 30 мин)

Действия

  1. Запустить coverage: pytest --cov=agent_comm --cov-branch --cov-report=html tests/
  2. Проанализировать отчёт htmlcov/index.html, найти непокрытые строки и ветки.
  3. Добавить тесты для непокрытых участков (например, редкие исключения, альтернативные ветки if).
  4. Повторять до достижения 95% branch coverage (минимально; target 95% с допуском 1%).
  5. Зафиксировать финальный отчёт в coverage.xml.

Ожидаемый результат этапа Покрытие >= 95% (линии + ветви). Тесты проходят без ошибок.

5. Критерии приемки (Definition of Done)

  • Все тесты запускаются одной командой pytest tests/ и проходят на 100%.
  • Покрытие кода модуля agent_comm (branch + line) составляет не менее 95% согласно coverage.py.
  • Включены тесты на: отправку point-to-point, publish/subscribe, unsubscription, валидацию обязательных полей.
  • Включены тесты на обработку ошибок: несуществующий получатель, превышение ёмкости, неверный формат, дубликат ID, таймаут.
  • Моки используются только для внешних зависимостей (брокер, логгер); внутренняя логика тестируется на реальных объектах.
  • Каждый тест атомарен, не зависит от других, использует уникальные фикстуры.
  • Генерация отчёта о покрытии в формате HTML и XML.
  • Код тестов оформлен по PEP 8, одобрен линтером ruff.
  • Документация: README с командами запуска и описанием структуры тестов.

6. Ожидаемый результат

Основной артефакт Папка tests/ с тестами и конфигурацией.

Содержание файлов

  • tests/__init__.py (пустой)
  • tests/test_message_bus.py — основные тесты.
  • tests/conftest.py — фикстуры (message_bus, sample_message, agent_stub).
  • pyproject.toml (или .coveragerc) с настройками coverage.
  • README.md с инструкцией по запуску.
  • (опционально) tests/test_errors.py, tests/test_integration.py для разделения.

Дополнительные результаты

  • Отчёт coverage в htmlcov/index.html (если не включено в gitignore).
  • Линтер ruff check . не выводит ошибок.

7. Возможные сложности и их решение

СложностьРешение
Асинхронные тесты зависают при ошибкахИспользовать pytest-asyncio с таймаутом: @pytest.mark.timeout(2); для каждого асинхронного теста добавить pytestmark = pytest.mark.asyncio
Невозможно измерить branch coverage для исключений, которые сложно вызватьНаписать тест с некорректным типом данных, передаваемым в метод; использовать pytest.raises и проверить, что ошибка логируется
Пересечение состояний между тестами (shared state в MessageBus)Каждая фикстура создаёт новый экземпляр шины; моки очищаются в autouse фикстуре
Большое количество тестов замедляет CIРазделить на slow/fast маркеры; slow-тесты запускать отдельно
Покрытие падает из-за недостижимого кода (например, # pragma: no cover)Разрешить исключать такие строки в .coveragerc с комментарием; убедиться, что это действительно недостижимо

8. Бюджет времени (оценка)

ЭтапОписаниеВремя
1Изучение спецификации, настройка фикстур30 мин
2Тесты базовой отправки/получения1 ч 30 мин
3Тесты обработки ошибок и граничных случаев1 ч
4Интеграционное тестирование с моками1 ч
5Анализ coverage и доведение до 95%30 мин
Итого4 ч 30 мин

Примечание Для первого раза (изучение асинхронного тестирования, моков) добавьте 1.5 часа на раскачку.

9. Связанные вопросы из базы знаний

ВопросТема
12Настройка pytest для асинхронных тестов
35Создание фикстур в pytest
78Измерение branch coverage в coverage.py
120Mock объектов в unittest.mock
156Проектирование протокола меж-агентской коммуникации
189Тестирование edge-кейсов с сообщениями
210Организация тестов для микросервисов
340Использование pydantic для валидации сообщений
415Параметризованные тесты в pytest
520Асинхронные очереди asyncio и их тестирование

10. Чек-лист самопроверки

  • Я создал структуру tests/ и настроил coverage в pyproject.toml?
  • Все тесты запускаются, зелёные, и покрытие действительно >=95%?
  • Я проверил, что каждый тест атомарен и не полагается на порядок выполнения?
  • Я написал хотя бы один тест для каждого исключения, описанного в exceptions.py?
  • Отчёт coverage не содержит неожиданно низких показателей в ключевых методах (send, publish, subscribe, _validate)?