Enhance private handlers structure and add database support
- Introduced a new `PrivateHandlers` class to encapsulate private message handling logic, improving organization and maintainability. - Added new dependencies in `requirements.txt` for database support with `aiosqlite`. - Updated the private handlers to utilize modular components for better separation of concerns and easier testing. - Implemented error handling and logging for improved robustness in message processing.
This commit is contained in:
174
tests/test_async_db.py
Normal file
174
tests/test_async_db.py
Normal file
@@ -0,0 +1,174 @@
|
||||
import pytest
|
||||
import asyncio
|
||||
import os
|
||||
import tempfile
|
||||
from database.async_db import AsyncBotDB
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def temp_db():
|
||||
"""Создает временную базу данных для тестирования."""
|
||||
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp:
|
||||
db_path = tmp.name
|
||||
|
||||
db = AsyncBotDB(db_path)
|
||||
yield db
|
||||
|
||||
# Очистка
|
||||
try:
|
||||
os.unlink(db_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def event_loop():
|
||||
"""Создает новый event loop для каждого теста."""
|
||||
loop = asyncio.new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_tables(temp_db):
|
||||
"""Тест создания таблиц."""
|
||||
await temp_db.create_tables()
|
||||
# Если не возникло исключение, значит таблицы созданы успешно
|
||||
assert True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_and_get_user(temp_db):
|
||||
"""Тест добавления и получения пользователя."""
|
||||
await temp_db.create_tables()
|
||||
|
||||
# Добавляем пользователя
|
||||
user_id = 12345
|
||||
first_name = "Test"
|
||||
full_name = "Test User"
|
||||
username = "testuser"
|
||||
|
||||
await temp_db.add_new_user(user_id, first_name, full_name, username)
|
||||
|
||||
# Проверяем существование
|
||||
exists = await temp_db.user_exists(user_id)
|
||||
assert exists is True
|
||||
|
||||
# Получаем информацию
|
||||
user_info = await temp_db.get_user_info(user_id)
|
||||
assert user_info is not None
|
||||
assert user_info['username'] == username
|
||||
assert user_info['full_name'] == full_name
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_blacklist_operations(temp_db):
|
||||
"""Тест операций с черным списком."""
|
||||
await temp_db.create_tables()
|
||||
|
||||
user_id = 12345
|
||||
user_name = "Test User"
|
||||
message = "Test ban"
|
||||
date_to_unban = "01-01-2025"
|
||||
|
||||
# Добавляем в черный список
|
||||
await temp_db.add_to_blacklist(user_id, user_name, message, date_to_unban)
|
||||
|
||||
# Проверяем наличие
|
||||
is_banned = await temp_db.check_blacklist(user_id)
|
||||
assert is_banned is True
|
||||
|
||||
# Получаем список
|
||||
banned_users = await temp_db.get_blacklist_users()
|
||||
assert len(banned_users) == 1
|
||||
assert banned_users[0][1] == user_id # user_id
|
||||
|
||||
# Удаляем из черного списка
|
||||
removed = await temp_db.remove_from_blacklist(user_id)
|
||||
assert removed is True
|
||||
|
||||
# Проверяем удаление
|
||||
is_banned = await temp_db.check_blacklist(user_id)
|
||||
assert is_banned is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_operations(temp_db):
|
||||
"""Тест операций с администраторами."""
|
||||
await temp_db.create_tables()
|
||||
|
||||
user_id = 12345
|
||||
role = "admin"
|
||||
|
||||
# Добавляем администратора
|
||||
await temp_db.add_admin(user_id, role)
|
||||
|
||||
# Проверяем права
|
||||
is_admin = await temp_db.is_admin(user_id)
|
||||
assert is_admin is True
|
||||
|
||||
# Удаляем администратора
|
||||
await temp_db.remove_admin(user_id)
|
||||
|
||||
# Проверяем удаление
|
||||
is_admin = await temp_db.is_admin(user_id)
|
||||
assert is_admin is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_audio_operations(temp_db):
|
||||
"""Тест операций с аудио."""
|
||||
await temp_db.create_tables()
|
||||
|
||||
user_id = 12345
|
||||
file_name = "test_audio.mp3"
|
||||
file_id = "test_file_id"
|
||||
|
||||
# Добавляем аудио запись
|
||||
await temp_db.add_audio_record(file_name, user_id, file_id)
|
||||
|
||||
# Получаем file_id
|
||||
retrieved_file_id = await temp_db.get_audio_file_id(user_id)
|
||||
assert retrieved_file_id == file_id
|
||||
|
||||
# Получаем имя файла
|
||||
retrieved_file_name = await temp_db.get_audio_file_name(user_id)
|
||||
assert retrieved_file_name == file_name
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_post_operations(temp_db):
|
||||
"""Тест операций с постами."""
|
||||
await temp_db.create_tables()
|
||||
|
||||
message_id = 12345
|
||||
text = "Test post text"
|
||||
author_id = 67890
|
||||
|
||||
# Добавляем пост
|
||||
await temp_db.add_post(message_id, text, author_id)
|
||||
|
||||
# Обновляем helper сообщение
|
||||
helper_message_id = 54321
|
||||
await temp_db.update_helper_message(message_id, helper_message_id)
|
||||
|
||||
# Получаем текст поста
|
||||
retrieved_text = await temp_db.get_post_text(helper_message_id)
|
||||
assert retrieved_text == text
|
||||
|
||||
# Получаем ID автора
|
||||
retrieved_author_id = await temp_db.get_author_id_by_helper_message(helper_message_id)
|
||||
assert retrieved_author_id == author_id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_error_handling(temp_db):
|
||||
"""Тест обработки ошибок."""
|
||||
# Пытаемся получить пользователя без создания таблиц
|
||||
with pytest.raises(Exception):
|
||||
await temp_db.user_exists(12345)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Запуск тестов
|
||||
pytest.main([__file__, "-v"])
|
||||
169
tests/test_refactored_private_handlers.py
Normal file
169
tests/test_refactored_private_handlers.py
Normal file
@@ -0,0 +1,169 @@
|
||||
"""Tests for refactored private handlers"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock, AsyncMock, MagicMock
|
||||
from aiogram import types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
|
||||
from helper_bot.handlers.private.private_handlers import (
|
||||
create_private_handlers, PrivateHandlers
|
||||
)
|
||||
from helper_bot.handlers.private.services import BotSettings
|
||||
from helper_bot.handlers.private.constants import FSM_STATES, BUTTON_TEXTS
|
||||
|
||||
|
||||
class TestPrivateHandlers:
|
||||
"""Test class for PrivateHandlers"""
|
||||
|
||||
@pytest.fixture
|
||||
def mock_db(self):
|
||||
"""Mock database"""
|
||||
db = Mock()
|
||||
db.user_exists.return_value = False
|
||||
db.add_new_user_in_db = Mock()
|
||||
db.update_date_for_user = Mock()
|
||||
db.update_info_about_stickers = Mock()
|
||||
db.add_post_in_db = Mock()
|
||||
db.add_new_message_in_db = Mock()
|
||||
db.update_helper_message_in_db = Mock()
|
||||
return db
|
||||
|
||||
@pytest.fixture
|
||||
def mock_settings(self):
|
||||
"""Mock bot settings"""
|
||||
return BotSettings(
|
||||
group_for_posts="test_posts",
|
||||
group_for_message="test_message",
|
||||
main_public="test_public",
|
||||
group_for_logs="test_logs",
|
||||
important_logs="test_important",
|
||||
preview_link="test_link",
|
||||
logs="test_logs_setting",
|
||||
test="test_test_setting"
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_message(self):
|
||||
"""Mock Telegram message"""
|
||||
message = Mock(spec=types.Message)
|
||||
message.from_user.id = 12345
|
||||
message.from_user.full_name = "Test User"
|
||||
message.from_user.username = "testuser"
|
||||
message.from_user.is_bot = False
|
||||
message.from_user.language_code = "ru"
|
||||
message.text = "test message"
|
||||
message.chat.id = 12345
|
||||
message.bot = Mock()
|
||||
message.bot.send_message = AsyncMock()
|
||||
message.forward = AsyncMock()
|
||||
message.answer = AsyncMock()
|
||||
message.answer_sticker = AsyncMock()
|
||||
return message
|
||||
|
||||
@pytest.fixture
|
||||
def mock_state(self):
|
||||
"""Mock FSM state"""
|
||||
state = Mock(spec=FSMContext)
|
||||
state.set_state = AsyncMock()
|
||||
state.get_state = AsyncMock(return_value=FSM_STATES["START"])
|
||||
return state
|
||||
|
||||
def test_create_private_handlers(self, mock_db, mock_settings):
|
||||
"""Test creating private handlers instance"""
|
||||
handlers = create_private_handlers(mock_db, mock_settings)
|
||||
assert isinstance(handlers, PrivateHandlers)
|
||||
assert handlers.db == mock_db
|
||||
assert handlers.settings == mock_settings
|
||||
|
||||
def test_private_handlers_initialization(self, mock_db, mock_settings):
|
||||
"""Test PrivateHandlers initialization"""
|
||||
handlers = PrivateHandlers(mock_db, mock_settings)
|
||||
assert handlers.db == mock_db
|
||||
assert handlers.settings == mock_settings
|
||||
assert handlers.user_service is not None
|
||||
assert handlers.post_service is not None
|
||||
assert handlers.sticker_service is not None
|
||||
assert handlers.router is not None
|
||||
|
||||
def test_handle_emoji_message(self, mock_db, mock_settings, mock_message, mock_state):
|
||||
"""Test emoji message handler"""
|
||||
handlers = create_private_handlers(mock_db, mock_settings)
|
||||
|
||||
# Mock the check_user_emoji function
|
||||
with pytest.MonkeyPatch().context() as m:
|
||||
m.setattr('helper_bot.handlers.private.private_handlers.check_user_emoji', lambda x: "😊")
|
||||
|
||||
# Test the handler
|
||||
handlers.handle_emoji_message(mock_message, mock_state)
|
||||
|
||||
# Verify state was set
|
||||
mock_state.set_state.assert_called_once_with(FSM_STATES["START"])
|
||||
|
||||
# Verify message was logged
|
||||
mock_message.forward.assert_called_once_with(chat_id=mock_settings.group_for_logs)
|
||||
|
||||
def test_handle_start_message(self, mock_db, mock_settings, mock_message, mock_state):
|
||||
"""Test start message handler"""
|
||||
handlers = create_private_handlers(mock_db, mock_settings)
|
||||
|
||||
# Mock the get_first_name and messages functions
|
||||
with pytest.MonkeyPatch().context() as m:
|
||||
m.setattr('helper_bot.handlers.private.private_handlers.get_first_name', lambda x: "Test")
|
||||
m.setattr('helper_bot.handlers.private.private_handlers.messages.get_message', lambda x, y: "Hello Test!")
|
||||
m.setattr('helper_bot.handlers.private.private_handlers.get_reply_keyboard', lambda x, y: Mock())
|
||||
|
||||
# Test the handler
|
||||
handlers.handle_start_message(mock_message, mock_state)
|
||||
|
||||
# Verify state was set
|
||||
mock_state.set_state.assert_called_once_with(FSM_STATES["START"])
|
||||
|
||||
# Verify user was ensured to exist
|
||||
mock_db.add_new_user_in_db.assert_called_once()
|
||||
mock_db.update_date_for_user.assert_called_once()
|
||||
|
||||
|
||||
class TestBotSettings:
|
||||
"""Test class for BotSettings dataclass"""
|
||||
|
||||
def test_bot_settings_creation(self):
|
||||
"""Test creating BotSettings instance"""
|
||||
settings = BotSettings(
|
||||
group_for_posts="posts",
|
||||
group_for_message="message",
|
||||
main_public="public",
|
||||
group_for_logs="logs",
|
||||
important_logs="important",
|
||||
preview_link="link",
|
||||
logs="logs_setting",
|
||||
test="test_setting"
|
||||
)
|
||||
|
||||
assert settings.group_for_posts == "posts"
|
||||
assert settings.group_for_message == "message"
|
||||
assert settings.main_public == "public"
|
||||
assert settings.group_for_logs == "logs"
|
||||
assert settings.important_logs == "important"
|
||||
assert settings.preview_link == "link"
|
||||
assert settings.logs == "logs_setting"
|
||||
assert settings.test == "test_setting"
|
||||
|
||||
|
||||
class TestConstants:
|
||||
"""Test class for constants"""
|
||||
|
||||
def test_fsm_states(self):
|
||||
"""Test FSM states constants"""
|
||||
assert FSM_STATES["START"] == "START"
|
||||
assert FSM_STATES["SUGGEST"] == "SUGGEST"
|
||||
assert FSM_STATES["PRE_CHAT"] == "PRE_CHAT"
|
||||
assert FSM_STATES["CHAT"] == "CHAT"
|
||||
|
||||
def test_button_texts(self):
|
||||
"""Test button text constants"""
|
||||
assert BUTTON_TEXTS["SUGGEST_POST"] == "📢Предложить свой пост"
|
||||
assert BUTTON_TEXTS["SAY_GOODBYE"] == "👋🏼Сказать пока!"
|
||||
assert BUTTON_TEXTS["LEAVE_CHAT"] == "Выйти из чата"
|
||||
assert BUTTON_TEXTS["RETURN_TO_BOT"] == "Вернуться в бота"
|
||||
assert BUTTON_TEXTS["WANT_STICKERS"] == "🤪Хочу стикеры"
|
||||
assert BUTTON_TEXTS["CONNECT_ADMIN"] == "📩Связаться с админами"
|
||||
Reference in New Issue
Block a user