Files
telegram-helper-bot/voice_bot/tests/test_voice_bot_architecture.py
Andrey d128e54694 Refactor project structure and remove obsolete files
- Deleted the Makefile, `README_TESTING.md`, and several deployment scripts to streamline the project.
- Updated `.dockerignore` to exclude unnecessary development files.
- Adjusted database schema comments for clarity.
- Refactored metrics handling in middleware for improved command extraction and logging.
- Enhanced command mappings for buttons and callbacks in constants for better maintainability.
- Start refactor voice bot
2025-09-01 00:54:10 +03:00

233 lines
9.1 KiB
Python

import pytest
from unittest.mock import Mock, AsyncMock, patch
from datetime import datetime
from voice_bot.handlers.services import VoiceBotService, AudioFileService
from voice_bot.handlers.exceptions import VoiceMessageError, AudioProcessingError
from voice_bot.handlers.utils import format_time_ago, plural_time
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
def test_get_random_audio_success(self, voice_service, mock_bot_db):
"""Тест успешного получения случайного аудио"""
mock_bot_db.check_listen_audio.return_value = ['audio1', 'audio2']
mock_bot_db.get_user_id_by_file_name.return_value = 123
mock_bot_db.get_date_by_file_name.return_value = '2025-01-01 12:00:00'
mock_bot_db.check_emoji_for_user.return_value = '😊'
result = 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] == '😊'
def test_get_random_audio_no_audio(self, voice_service, mock_bot_db):
"""Тест получения аудио когда их нет"""
mock_bot_db.check_listen_audio.return_value = []
result = voice_service.get_random_audio(456)
assert result is None
def test_mark_audio_as_listened_success(self, voice_service, mock_bot_db):
"""Тест успешной пометки аудио как прослушанного"""
voice_service.mark_audio_as_listened('test_audio', 123)
mock_bot_db.mark_listened_audio.assert_called_once_with('test_audio', user_id=123)
def test_clear_user_listenings_success(self, voice_service, mock_bot_db):
"""Тест успешной очистки прослушиваний"""
voice_service.clear_user_listenings(123)
mock_bot_db.delete_listen_count_for_user.assert_called_once_with(123)
class TestAudioFileService:
"""Тесты для AudioFileService"""
@pytest.fixture
def mock_bot_db(self):
"""Мок для базы данных"""
return Mock()
@pytest.fixture
def audio_service(self, mock_bot_db):
"""Экземпляр AudioFileService для тестов"""
return AudioFileService(mock_bot_db)
def test_generate_file_name_first_audio(self, audio_service, mock_bot_db):
"""Тест генерации имени для первого аудио пользователя"""
mock_bot_db.get_last_user_audio_record.return_value = False
file_name = audio_service.generate_file_name(123)
assert file_name == 'message_from_123_number_1'
def test_generate_file_name_subsequent_audio(self, audio_service, mock_bot_db):
"""Тест генерации имени для последующих аудио пользователя"""
mock_bot_db.get_last_user_audio_record.return_value = True
mock_bot_db.get_path_for_audio_record.return_value = 'existing_file'
mock_bot_db.get_id_for_audio_record.return_value = 5
with patch('pathlib.Path.exists') as mock_exists:
mock_exists.return_value = True
file_name = audio_service.generate_file_name(123)
assert file_name == 'message_from_123_number_6'
def test_save_audio_file_success(self, audio_service, mock_bot_db):
"""Тест успешного сохранения аудио файла в БД"""
file_name = 'test_file'
user_id = 123
file_id = 1
date_added = datetime.now()
audio_service.save_audio_file(file_name, user_id, file_id, date_added)
mock_bot_db.add_audio_record.assert_called_once_with(
file_name, user_id, date_added, 0, file_id
)
class TestUtils:
"""Тесты для утилит"""
def test_plural_time_minutes(self):
"""Тест множественного числа для минут"""
assert plural_time(1, 1) == '1 минуту'
assert plural_time(1, 2) == '2 минуты'
assert plural_time(1, 5) == '5 минут'
assert plural_time(1, 11) == '11 минут'
assert plural_time(1, 21) == '21 минуту'
def test_plural_time_hours(self):
"""Тест множественного числа для часов"""
assert plural_time(2, 1) == '1 час'
assert plural_time(2, 2) == '2 часа'
assert plural_time(2, 5) == '5 часов'
assert plural_time(2, 11) == '11 часов'
assert plural_time(2, 21) == '21 час'
def test_plural_time_days(self):
"""Тест множественного числа для дней"""
assert plural_time(3, 1) == '1 день'
assert plural_time(3, 2) == '2 дня'
assert plural_time(3, 5) == '5 дней'
assert plural_time(3, 11) == '11 дней'
assert plural_time(3, 21) == '21 день'
def test_format_time_ago_minutes(self):
"""Тест форматирования времени для минут"""
from datetime import datetime, timedelta
# Создаем время 30 минут назад
past_time = datetime.now() - timedelta(minutes=30)
time_str = past_time.strftime("%Y-%m-%d %H:%M:%S")
result = format_time_ago(time_str)
assert '30 минут' in result
assert 'назад' in result
def test_format_time_ago_hours(self):
"""Тест форматирования времени для часов"""
from datetime import datetime, timedelta
# Создаем время 2 часа назад
past_time = datetime.now() - timedelta(hours=2)
time_str = past_time.strftime("%Y-%m-%d %H:%M:%S")
result = format_time_ago(time_str)
assert '2 часа' in result
assert 'назад' in result
def test_format_time_ago_days(self):
"""Тест форматирования времени для дней"""
from datetime import datetime, timedelta
# Создаем время 3 дня назад
past_time = datetime.now() - timedelta(days=3)
time_str = past_time.strftime("%Y-%m-%d %H:%M:%S")
result = format_time_ago(time_str)
assert '3 дня' in result
assert 'назад' in result
class TestExceptions:
"""Тесты для исключений"""
def test_voice_bot_error_inheritance(self):
"""Тест наследования исключений"""
assert issubclass(VoiceMessageError, VoiceBotError)
assert issubclass(AudioProcessingError, VoiceBotError)
assert issubclass(DatabaseError, VoiceBotError)
assert issubclass(FileOperationError, VoiceBotError)
def test_exception_messages(self):
"""Тест сообщений исключений"""
try:
raise VoiceMessageError("Тестовая ошибка")
except VoiceMessageError as e:
assert str(e) == "Тестовая ошибка"
try:
raise AudioProcessingError("Ошибка обработки")
except AudioProcessingError as e:
assert str(e) == "Ошибка обработки"
if __name__ == '__main__':
pytest.main([__file__])