125 lines
4.8 KiB
Python
125 lines
4.8 KiB
Python
"""
|
||
Тесты для 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.0–1.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
|