4 testing
AI Wiki Bot edited this page 2026-09-16 19:34:21 +00:00
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.

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

Юнит-тесты проекта GigaAM-Multilingual ASR Server обеспечивают проверку двух ключевых аспектов логики сервера: механизма выбора моделей (мультимодельная маршрутизация запросов) и обработки временных меток (преобразование символьных CTC-меток в словесные интервалы). Набор тестов выполняется на каждом этапе сборки Docker-образа, что гарантирует стабильность API перед публикацией.

Назначение и цели

Тесты покрывают следующие функциональные области:

  1. Выбор моделей — верификация того, что поле model в запросе корректно резолвится в загруженную модель, а неизвестные имена отклоняются с кодом 404.
  2. Обработка меток времени — проверка функции _chars_to_words(), которая группирует символные токены CTC с их временными позициями в словесные интервалы (words).
  3. Совместимость с OpenAI API — подтверждение, что формат запроса и ответа соответствует контракту официального клиента OpenAI, включая обработку массивного поля timestamp_granularities[].
  4. CORS и preflight — обеспечение работоспособности опциональных запросов OPTIONS для клиентов, использующих CORS-preflight (браузеры, прокси LiteLLM).

Структура файлов

Набор тестов состоит из двух модулей:

Файл Область покрытия
tests/test_models.py Логика resolve_model(), конечная точка /v1/models, обязательность поля model, CORS-preflight, парсинг CORS_ORIGINS
tests/test_words.py Функция _chars_to_words(), обработка граничных случаев (пустые строки, пробелы), интеграция с конечной точкой транскрипции

Конфигурация запуска задаётся в файле pytest.ini:

[pytest]
testpaths = tests

Ключевые компоненты

Модуль test_models.py

Этот модуль тестирует механизм мультимодельной маршрутизации. Основные тесты:

  • test_resolve_model_unknown_raises_404 — проверяет, что запрос с несуществующим именем модели вызывает исключение 404. Это соответствует контракту OpenAI API, где поле model является обязательным и не допускает fallback.
  • test_resolve_model_no_aliases — убеждается, что алиасы больше не поддерживаются (убраны начиная с версии 0.1.2).
  • test_resolve_model_exact_and_by_onnx_name — верифицирует точное сопоставление имени модели как по alias, так и по внутреннему имени ONNX.
  • test_transcriptions_requires_model — подтверждает, что POST-запрос без поля model отклоняется с кодом 422.
  • test_options_preflight_allowed — проверяет, что OPTIONS /v1/audio/transcriptions возвращает 200 (CORS-preflight). Без этого клиенты, делающие preflight перед основным запросом, получают 405 Method Not Allowed.
  • test_cors_origins_parsing — тестирует функцию _parse_cors_origins() на различных входных значениях: "*", список через запятую, пустая строка.
  • test_models_endpoint_lists_all — убеждается, что GET /v1/models возвращает все загруженные модели.

Все тесты используют фикстуру monkeypatch для подмены состояния _state и асинхронных функций, что позволяет избежать загрузки реальных ONNX-моделей (которые занимают сотни мегабайт).

Модуль test_words.py

Этот модуль фокусируется на обработке временных меток:

  • test_chars_to_words_basic — базовый сценарий: преобразование списка символов ["н", "и", "ч", "ь", "и", "х", " ", "д", "у", "б"] с метками времени [0.0, 0.1, ..., 1.0] в два слова: {"word": "ничьих", "start": 0.0, "end": 0.5} и {"word": "дуб", "start": 0.8, "end": 1.0}.
  • test_chars_to_words_leading_trailing_spaces — проверяет корректную обрезку ведущих и завершающих пробелов.
  • test_chars_to_words_empty — обрабатывает пустой ввод.
  • test_word_granularities_form_field — регрессионный тест: OpenAI-клиенты отправляют массивное поле как timestamp_granularities[] (с квадратными скобками). Сервер должен принимать этот формат, иначе флаг word_timestamps остаётся False, и поле words молча отсутствует в ответе.

Для интеграционного теста используется заглушка _FakeModel, имитирующая поведение адаптера onnx_asr без загрузки реальной модели.

Связь с другими модулями

Тесты напрямую зависят от следующих компонентов сервера:

  • src/gigam_asr/server.py — основной модуль, содержащий:
    • Функцию resolve_model() — маппинг имени модели в запросе на загруженный адаптер.
    • Функцию _chars_to_words() — группировка символьных CTC-меток в словесные интервалы.
    • Функцию _parse_cors_origins() — парсинг переменной окружения CORS_ORIGINS.
    • Конечную точку POST /v1/audio/transcriptions — основная логика транскрипции.
    • Конечную точку GET /v1/models — список доступных моделей.

Дополнительные контексты:

  • Архитектура — описание взаимодействия FastAPI, ONNX Runtime и Silero VAD.
  • Справочник API — детальные спецификации параметров запросов и формата ответов.
  • Конфигурация — перечень переменных окружения, влияющих на поведение тестируемых функций.
  • CI/CD и автоматизация — настройка конвейеров, включающих запуск тестов при сборке образа.

Примеры использования

Запуск локально

# Установка зависимостей разработки
pip install pytest httpx

# Запуск всех тестов
python -m pytest tests/ -v

# Запуск конкретного модуля
python -m pytest tests/test_models.py -v

# Запуск с подробным выводом ошибок
python -m pytest tests/ -vv --tb=long

Интеграция в Docker-сборку

В файле Dockerfile тесты выполняются на этапе сборки:

# 5. Тесты при сборке (httpx нужен только для ASGI-теста, не входит в runtime)
RUN pip install --no-cache-dir pytest httpx && python -m pytest tests/ -q

Это гарантирует, что образ публикуется в Container Registry только после успешного прохождения всех юнит-тестов.

Типовой тестовый сценарий

Рассмотрим типовой тест из test_models.py:

def test_resolve_model_unknown_raises_404(monkeypatch):
    """Неизвестное имя модели должно вызывать HTTPException 404."""
    from fastapi import HTTPException
    
    monkeypatch.setattr("gigam_asr.server._state", {
        "models": {"gigaam-multilingual-large-ctc": {"name": "large"}}
    })
    
    with pytest.raises(HTTPException) as exc_info:
        resolve_model("nonexistent-model")
    
    assert exc_info.value.status_code == 404

Такой подход позволяет изолированно проверить логику резолвинга без инициализации реальных моделей.

Рекомендации по расширению

При добавлении новых функций рекомендуется:

  1. Создавать отдельные тестовые файлы для каждой логической области (например, test_vad.py для тестирования сегментации Silero VAD).
  2. Использовать фикстуры monkeypatch для подмены внешних зависимостей (ONNX-модели, ffmpeg).
  3. Добавлять регрессионные тесты для обнаруженных дефектов (пример: test_word_granularities_form_field был добавлен после исправления проблемы с форматом массивного поля).
  4. Обеспечивать покрытие граничных случаев: пустые входы, максимальные длины, неверные типы данных.

Текущий набор тестов обеспечивает надёжную защиту основных контрактных обязательств сервера перед клиентами OpenAI-совместимого API.