Переписал почти все тесты

feat: улучшено логирование и обработка скорингов в PostService и RagApiClient

- Добавлены отладочные сообщения для передачи скорингов в функции обработки постов.
- Обновлено логирование успешного получения скорингов из RAG API с дополнительной информацией.
- Оптимизирована обработка скорингов в функции get_text_message для улучшения отладки.
- Обновлены тесты для проверки новых функциональных возможностей и обработки ошибок.
This commit is contained in:
2026-01-30 00:55:47 +03:00
parent e87f4af82f
commit a5faa4bdc6
27 changed files with 4320 additions and 8 deletions

View File

@@ -0,0 +1,123 @@
"""
Тесты для helper_bot.services.scoring.deepseek_service (DeepSeekService).
"""
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from helper_bot.services.scoring.deepseek_service import DeepSeekService
from helper_bot.services.scoring.exceptions import (
DeepSeekAPIError,
ScoringError,
TextTooShortError,
)
@pytest.mark.unit
class TestDeepSeekServiceInit:
"""Тесты инициализации DeepSeekService."""
def test_init_with_api_key_enabled(self):
"""При переданном api_key сервис включён."""
with patch("helper_bot.services.scoring.deepseek_service.httpx.AsyncClient", None):
service = DeepSeekService(api_key="key")
assert service.is_enabled is True
assert service.source_name == "deepseek"
def test_init_without_api_key_disabled(self):
"""Без api_key сервис отключён."""
service = DeepSeekService(api_key=None)
assert service.is_enabled is False
def test_init_default_url_and_model(self):
"""Используются DEFAULT_API_URL и DEFAULT_MODEL."""
service = DeepSeekService(api_key="k")
assert service.api_url == DeepSeekService.DEFAULT_API_URL
assert service.model == DeepSeekService.DEFAULT_MODEL
@pytest.mark.unit
class TestDeepSeekServiceHelpers:
"""Тесты _clean_text и _parse_score_response."""
def test_clean_text_strips_and_collapses_whitespace(self):
"""_clean_text убирает лишние пробелы и переносы."""
service = DeepSeekService(api_key="k")
assert service._clean_text(" a b \n c ") == "a b c"
def test_clean_text_empty_returns_empty(self):
"""_clean_text для пустой строки возвращает ''."""
service = DeepSeekService(api_key="k")
assert service._clean_text("") == ""
assert service._clean_text(" ") == ""
def test_parse_score_response_valid_number(self):
"""_parse_score_response парсит число."""
service = DeepSeekService(api_key="k")
assert service._parse_score_response("0.75") == 0.75
assert service._parse_score_response("1.0") == 1.0
assert service._parse_score_response("0") == 0.0
def test_parse_score_response_clamps_to_range(self):
"""_parse_score_response ограничивает значение 0.01.0."""
service = DeepSeekService(api_key="k")
assert service._parse_score_response("1.5") == 1.0
assert service._parse_score_response("-0.1") == 0.0
def test_parse_score_response_invalid_raises(self):
"""_parse_score_response при невалидном ответе выбрасывает DeepSeekAPIError."""
service = DeepSeekService(api_key="k")
with pytest.raises(DeepSeekAPIError, match="распарсить"):
service._parse_score_response("not a number")
@pytest.mark.unit
@pytest.mark.asyncio
class TestDeepSeekServiceCalculateScore:
"""Тесты calculate_score."""
@pytest.fixture
def service(self):
"""Сервис с api_key."""
return DeepSeekService(api_key="key", min_text_length=3)
async def test_disabled_raises_scoring_error(self, service):
"""При отключённом сервисе — ScoringError."""
service._enabled = False
with pytest.raises(ScoringError, match="отключен"):
await service.calculate_score("достаточно длинный текст")
async def test_text_too_short_raises(self, service):
"""Текст короче min_text_length — TextTooShortError."""
with pytest.raises(TextTooShortError, match="короткий"):
await service.calculate_score("ab")
async def test_success_returns_scoring_result(self, service):
"""Успешный запрос возвращает ScoringResult."""
with patch.object(
service,
"_make_api_request",
new_callable=AsyncMock,
return_value=0.82,
):
result = await service.calculate_score("Текст поста для оценки")
assert result.score == 0.82
assert result.source == "deepseek"
assert result.model == service.model
@pytest.mark.unit
class TestDeepSeekServiceStats:
"""Тесты get_stats."""
def test_get_stats_returns_dict(self):
"""get_stats возвращает словарь с enabled, model, api_url, timeout, max_retries."""
service = DeepSeekService(api_key="k", timeout=60, max_retries=5)
stats = service.get_stats()
assert stats["enabled"] is True
assert stats["model"] == service.model
assert stats["api_url"] == service.api_url
assert stats["timeout"] == 60
assert stats["max_retries"] == 5