Files
telegram-helper-bot/tests/test_voice_bot_architecture.py
2026-02-02 00:13:33 +03:00

315 lines
11 KiB
Python
Raw Permalink Blame History

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.
from datetime import datetime
from pathlib import Path
from unittest.mock import AsyncMock, Mock, patch
import pytest
from helper_bot.handlers.voice.exceptions import AudioProcessingError, VoiceMessageError
from helper_bot.handlers.voice.services import VoiceBotService
from helper_bot.handlers.voice.utils import (
get_last_message_text,
get_user_emoji_safe,
validate_voice_message,
)
class TestVoiceBotService:
"""Тесты для VoiceBotService"""
@pytest.fixture
def mock_bot_db(self):
"""Мок для базы данных"""
mock_db = Mock()
mock_db.settings = {
"Settings": {"logs": True},
"Telegram": {"important_logs": "test_chat_id"},
}
return mock_db
@pytest.fixture
def mock_settings(self):
"""Мок для настроек"""
return {"Settings": {"logs": True}, "Telegram": {"preview_link": True}}
@pytest.fixture
def voice_service(self, mock_bot_db, mock_settings):
"""Экземпляр VoiceBotService для тестов"""
return VoiceBotService(mock_bot_db, mock_settings)
@pytest.mark.asyncio
async def test_get_welcome_sticker_success(self, voice_service, mock_settings):
"""Тест успешного получения стикера"""
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = ["/path/to/sticker1.tgs", "/path/to/sticker2.tgs"]
sticker = await voice_service.get_welcome_sticker()
assert sticker is not None
mock_rglob.assert_called_once()
@pytest.mark.asyncio
async def test_get_welcome_sticker_no_stickers(self, voice_service, mock_settings):
"""Тест получения стикера когда их нет"""
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = []
sticker = await voice_service.get_welcome_sticker()
assert sticker is None
@pytest.mark.asyncio
async def test_get_random_audio_success(self, voice_service, mock_bot_db):
"""Тест успешного получения случайного аудио"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=["audio1", "audio2"])
mock_bot_db.get_user_id_by_file_name = AsyncMock(return_value=123)
mock_bot_db.get_date_by_file_name = AsyncMock(
return_value="2025-01-01 12:00:00"
)
mock_bot_db.get_user_emoji = AsyncMock(return_value="😊")
result = await voice_service.get_random_audio(456)
assert result is not None
assert len(result) == 3
assert result[0] in ["audio1", "audio2"]
assert result[1] == "2025-01-01 12:00:00"
assert result[2] == "😊"
@pytest.mark.asyncio
async def test_get_random_audio_no_audio(self, voice_service, mock_bot_db):
"""Тест получения аудио когда их нет"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
result = await voice_service.get_random_audio(456)
assert result is None
@pytest.mark.asyncio
async def test_mark_audio_as_listened_success(self, voice_service, mock_bot_db):
"""Тест успешной пометки аудио как прослушанного"""
mock_bot_db.mark_listened_audio = AsyncMock()
await voice_service.mark_audio_as_listened("test_audio", 123)
mock_bot_db.mark_listened_audio.assert_called_once_with(
"test_audio", user_id=123
)
@pytest.mark.asyncio
async def test_clear_user_listenings_success(self, voice_service, mock_bot_db):
"""Тест успешной очистки прослушиваний"""
mock_bot_db.delete_listen_count_for_user = AsyncMock()
await voice_service.clear_user_listenings(123)
mock_bot_db.delete_listen_count_for_user.assert_called_once_with(123)
@pytest.mark.asyncio
async def test_get_remaining_audio_count_success(self, voice_service, mock_bot_db):
"""Тест получения количества оставшихся аудио"""
mock_bot_db.check_listen_audio = AsyncMock(
return_value=["audio1", "audio2", "audio3"]
)
result = await voice_service.get_remaining_audio_count(123)
assert result == 3
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
@pytest.mark.asyncio
async def test_get_remaining_audio_count_zero(self, voice_service, mock_bot_db):
"""Тест получения количества оставшихся аудио когда их нет"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
result = await voice_service.get_remaining_audio_count(123)
assert result == 0
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
@pytest.mark.asyncio
async def test_send_welcome_messages_success(
self, voice_service, mock_bot_db, mock_settings
):
"""Тест успешной отправки приветственных сообщений."""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.answer = AsyncMock()
mock_message.answer.return_value = Mock()
mock_message.answer_sticker = AsyncMock()
with patch.object(
voice_service,
"get_welcome_sticker",
new_callable=AsyncMock,
return_value="test_sticker.tgs",
):
with patch(
"helper_bot.handlers.voice.services.asyncio.sleep",
new_callable=AsyncMock,
):
await voice_service.send_welcome_messages(mock_message, "😊")
assert mock_message.answer.call_count >= 1
@pytest.mark.asyncio
async def test_send_welcome_messages_no_sticker(
self, voice_service, mock_bot_db, mock_settings
):
"""Тест отправки приветственных сообщений без стикера."""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.answer = AsyncMock()
mock_message.answer.return_value = Mock()
with patch.object(
voice_service,
"get_welcome_sticker",
new_callable=AsyncMock,
return_value=None,
):
with patch(
"helper_bot.handlers.voice.services.asyncio.sleep",
new_callable=AsyncMock,
):
await voice_service.send_welcome_messages(mock_message, "😊")
assert mock_message.answer.call_count >= 1
class TestVoiceHandlers:
"""Тесты для VoiceHandlers"""
@pytest.fixture
def mock_db(self):
"""Мок для базы данных"""
return Mock()
@pytest.fixture
def mock_settings(self):
"""Мок для настроек"""
return {
"Telegram": {
"group_for_logs": "test_logs_chat",
"group_for_posts": "test_posts_chat",
"preview_link": True,
}
}
@pytest.fixture
def voice_handlers(self, mock_db, mock_settings):
"""Экземпляр VoiceHandlers для тестов"""
from helper_bot.handlers.voice.voice_handler import VoiceHandlers
return VoiceHandlers(mock_db, mock_settings)
def test_voice_handlers_initialization(self, voice_handlers):
"""Тест инициализации VoiceHandlers"""
assert voice_handlers.db is not None
assert voice_handlers.settings is not None
assert voice_handlers.router is not None
def test_setup_handlers(self, voice_handlers):
"""Тест настройки обработчиков"""
# Проверяем, что роутер содержит обработчики
assert len(voice_handlers.router.message.handlers) > 0
class TestUtils:
"""Тесты для утилит"""
@pytest.fixture
def mock_bot_db(self):
"""Мок для базы данных"""
return Mock()
@pytest.mark.asyncio
async def test_get_last_message_text(self, mock_bot_db):
"""Тест получения последнего сообщения"""
# Возвращаем UNIX timestamp
mock_bot_db.last_date_audio = AsyncMock(
return_value=1641034800
) # 2022-01-01 12:00:00
result = await get_last_message_text(mock_bot_db)
assert result is not None
assert (
"минут" in result
or "часа" in result
or "дня" in result
or "день" in result
or "дней" in result
)
mock_bot_db.last_date_audio.assert_called_once()
@pytest.mark.asyncio
async def test_validate_voice_message_valid(self):
"""Тест валидации голосового сообщения"""
mock_message = Mock()
mock_message.content_type = "voice"
mock_message.voice = Mock()
result = await validate_voice_message(mock_message)
assert result is True
@pytest.mark.asyncio
async def test_validate_voice_message_invalid(self):
"""Тест валидации невалидного сообщения"""
mock_message = Mock()
mock_message.voice = None
result = await validate_voice_message(mock_message)
assert result is False
@pytest.mark.asyncio
async def test_get_user_emoji_safe(self, mock_bot_db):
"""Тест безопасного получения эмодзи пользователя"""
mock_bot_db.get_user_emoji = AsyncMock(return_value="😊")
result = await get_user_emoji_safe(mock_bot_db, 123)
assert result == "😊"
mock_bot_db.get_user_emoji.assert_called_once_with(123)
@pytest.mark.asyncio
async def test_get_user_emoji_safe_none(self, mock_bot_db):
"""Тест безопасного получения эмодзи когда его нет"""
mock_bot_db.get_user_emoji = AsyncMock(return_value=None)
result = await get_user_emoji_safe(mock_bot_db, 123)
assert result == "😊"
@pytest.mark.asyncio
async def test_get_user_emoji_safe_error(self, mock_bot_db):
"""Тест безопасного получения эмодзи при ошибке"""
mock_bot_db.get_user_emoji = AsyncMock(return_value="Ошибка")
result = await get_user_emoji_safe(mock_bot_db, 123)
assert result == "Ошибка"
class TestExceptions:
"""Тесты для исключений"""
def test_voice_message_error(self):
"""Тест VoiceMessageError"""
try:
raise VoiceMessageError("Тестовая ошибка")
except VoiceMessageError as e:
assert str(e) == "Тестовая ошибка"
def test_audio_processing_error(self):
"""Тест AudioProcessingError"""
try:
raise AudioProcessingError("Ошибка обработки")
except AudioProcessingError as e:
assert str(e) == "Ошибка обработки"
if __name__ == "__main__":
pytest.main([__file__])