Files
telegram-helper-bot/tests/test_error_handling.py

340 lines
22 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.
# Импортируем моки в самом начале
import tests.mocks
import pytest
from unittest.mock import Mock, AsyncMock, patch
from aiogram.types import Message, User, Chat
from helper_bot.handlers.private.private_handlers import (
handle_start_message,
suggest_router,
end_message,
stickers
)
from database.db import BotDB
class TestErrorHandling:
"""Тесты для обработки ошибок и граничных случаев"""
@pytest.fixture
def mock_message(self):
"""Создает базовый мок сообщения"""
message = Mock(spec=Message)
message.from_user = Mock(spec=User)
message.from_user.id = 123456
message.from_user.full_name = "Test User"
message.from_user.username = "testuser"
message.from_user.first_name = "Test"
message.from_user.is_bot = False
message.from_user.language_code = "ru"
message.chat = Mock(spec=Chat)
message.chat.id = 123456
message.chat.type = "private"
message.message_id = 1
message.forward = AsyncMock()
message.answer = AsyncMock()
message.answer_sticker = AsyncMock()
message.bot.send_message = AsyncMock()
return message
@pytest.fixture
def mock_state(self):
"""Создает мок состояния"""
state = Mock()
state.set_state = AsyncMock()
state.get_state = AsyncMock(return_value="START")
return state
@pytest.fixture
def mock_db(self):
"""Создает мок базы данных"""
db = Mock(spec=BotDB)
db.user_exists = Mock(return_value=False)
db.add_new_user_in_db = Mock()
db.update_date_for_user = Mock()
db.update_username_and_full_name = Mock()
db.add_post_in_db = Mock()
db.update_info_about_stickers = Mock()
return db
@pytest.mark.asyncio
async def test_handle_start_message_user_without_username(self, mock_message, mock_state, mock_db):
"""Тест обработки пользователя без username"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.Path') as mock_path:
with patch('helper_bot.handlers.private.private_handlers.FSInputFile') as mock_fs:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков
mock_message.from_user.username = None
mock_keyboard.return_value = Mock()
mock_messages.return_value = "Привет!"
mock_path.return_value.rglob.return_value = ["sticker1.tgs"]
mock_fs.return_value = "sticker_file"
# Выполнение теста
await handle_start_message(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called()
# Проверяем, что отправлено сообщение о пользователе без username
call_args = mock_message.bot.send_message.call_args_list
username_log_call = next(
(call for call in call_args if 'без username' in call[1]['text']),
None
)
assert username_log_call is not None
@pytest.mark.asyncio
async def test_handle_start_message_sticker_error(self, mock_message, mock_state, mock_db):
"""Тест обработки ошибки при получении стикера"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.Path') as mock_path:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков с ошибкой
mock_path.return_value.rglob.side_effect = Exception("Sticker error")
mock_keyboard.return_value = Mock()
mock_messages.return_value = "Привет!"
# Выполнение теста
await handle_start_message(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called()
# Проверяем, что отправлено сообщение об ошибке
call_args = mock_message.bot.send_message.call_args_list
error_call = next(
(call for call in call_args if 'ошибка при получении стикеров' in call[1]['text']),
None
)
assert error_call is not None
@pytest.mark.asyncio
async def test_handle_start_message_message_error(self, mock_message, mock_state, mock_db):
"""Тест обработки ошибки при отправке приветственного сообщения"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.Path') as mock_path:
with patch('helper_bot.handlers.private.private_handlers.FSInputFile') as mock_fs:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков
mock_keyboard.return_value = Mock()
mock_messages.side_effect = Exception("Message error")
mock_path.return_value.rglob.return_value = ["sticker1.tgs"]
mock_fs.return_value = "sticker_file"
# Выполнение теста
await handle_start_message(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called()
# Проверяем, что отправлено сообщение об ошибке
call_args = mock_message.bot.send_message.call_args_list
# Проверяем, что было отправлено хотя бы одно сообщение
assert len(call_args) > 0
# Проверяем, что в одном из сообщений есть текст об ошибке
error_found = False
for call in call_args:
text = call.kwargs.get('text', '') or (call[0][1] if len(call[0]) > 1 else '')
if 'Произошла ошибка' in text:
error_found = True
break
assert error_found
@pytest.mark.asyncio
async def test_suggest_router_exception_handling(self, mock_message, mock_state):
"""Тест обработки исключений в suggest_router"""
with patch('helper_bot.handlers.private.private_handlers.BotDB') as mock_db:
with patch('helper_bot.handlers.private.private_handlers.get_text_message') as mock_get_text:
# Настройка моков с ошибкой
mock_message.content_type = 'text'
mock_message.text = 'Тестовый пост'
mock_message.media_group_id = None
mock_get_text.side_effect = Exception("Processing error")
# Выполнение теста
await suggest_router(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called_once()
call_args = mock_message.bot.send_message.call_args
assert 'Произошла ошибка' in call_args[1]['text']
@pytest.mark.asyncio
async def test_end_message_sticker_error(self, mock_message, mock_state):
"""Тест обработки ошибки при получении стикера в end_message"""
with patch('helper_bot.handlers.private.private_handlers.Path') as mock_path:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков с ошибкой
mock_message.text = '👋🏼Сказать пока!'
mock_path.return_value.rglob.side_effect = Exception("Sticker error")
mock_messages.return_value = "До свидания!"
# Выполнение теста
await end_message(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called()
call_args = mock_message.bot.send_message.call_args_list
# Проверяем, что в одном из сообщений есть текст об ошибке
error_found = False
for call in call_args:
text = call.kwargs.get('text', '') or (call[0][1] if len(call[0]) > 1 else '')
if 'Произошла ошибка' in text:
error_found = True
break
assert error_found
@pytest.mark.asyncio
async def test_end_message_message_error(self, mock_message, mock_state):
"""Тест обработки ошибки при отправке сообщения в end_message"""
with patch('helper_bot.handlers.private.private_handlers.Path') as mock_path:
with patch('helper_bot.handlers.private.private_handlers.FSInputFile') as mock_fs:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков
mock_message.text = '👋🏼Сказать пока!'
mock_path.return_value.rglob.return_value = ["sticker1.tgs"]
mock_fs.return_value = "sticker_file"
mock_messages.side_effect = Exception("Message error")
# Выполнение теста
await end_message(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called()
call_args = mock_message.bot.send_message.call_args_list
# Проверяем, что в одном из сообщений есть текст об ошибке
error_found = False
for call in call_args:
text = call.kwargs.get('text', '') or (call[0][1] if len(call[0]) > 1 else '')
if 'Произошла ошибка' in text:
error_found = True
break
assert error_found
@pytest.mark.asyncio
async def test_stickers_exception_handling(self, mock_message, mock_state, mock_db):
"""Тест обработки исключений в stickers"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
# Настройка моков с ошибкой
mock_message.text = '🤪Хочу стикеры'
mock_db.update_info_about_stickers.side_effect = Exception("Database error")
mock_keyboard.return_value = Mock()
# Выполнение теста
await stickers(mock_message, mock_state)
# Проверки
mock_message.bot.send_message.assert_called_once()
call_args = mock_message.bot.send_message.call_args
assert 'Произошла ошибка' in call_args[1]['text']
@pytest.mark.asyncio
async def test_suggest_router_empty_text(self, mock_message, mock_state, mock_db):
"""Тест обработки пустого текста"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_text_message') as mock_get_text:
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard_for_post') as mock_keyboard_post:
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.send_text_message') as mock_send:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков
mock_message.content_type = 'text'
mock_message.text = ''
mock_message.media_group_id = None
mock_get_text.return_value = ''
mock_keyboard_post.return_value = Mock()
mock_keyboard.return_value = Mock()
mock_send.return_value = 123
mock_messages.return_value = "Пост отправлен!"
# Выполнение теста
await suggest_router(mock_message, mock_state)
# Проверки - даже пустой текст должен обрабатываться
mock_message.forward.assert_called_once()
mock_send.assert_called()
mock_db.add_post_in_db.assert_called_once()
@pytest.mark.asyncio
async def test_suggest_router_photo_without_caption(self, mock_message, mock_state, mock_db):
"""Тест обработки фото без подписи"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard_for_post') as mock_keyboard_post:
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.send_photo_message') as mock_send_photo:
with patch('helper_bot.handlers.private.private_handlers.add_in_db_media') as mock_add_media:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков для фото без подписи
mock_message.content_type = 'photo'
mock_message.caption = None
mock_message.media_group_id = None
mock_message.photo = [Mock()]
mock_message.photo[-1].file_id = 'photo_file_id'
mock_keyboard_post.return_value = Mock()
mock_keyboard.return_value = Mock()
mock_send_photo.return_value = Mock()
mock_send_photo.return_value.message_id = 123
mock_send_photo.return_value.caption = ''
mock_messages.return_value = "Фото отправлено!"
# Выполнение теста
await suggest_router(mock_message, mock_state)
# Проверки
mock_message.forward.assert_called_once()
mock_send_photo.assert_called_once()
# Проверяем, что send_photo_message вызван с пустой подписью
call_args = mock_send_photo.call_args
assert call_args.kwargs.get('caption', '') == ''
@pytest.mark.asyncio
async def test_suggest_router_media_group_without_caption(self, mock_message, mock_state, mock_db):
"""Тест обработки медиагруппы без подписи"""
with patch('helper_bot.handlers.private.private_handlers.BotDB', mock_db):
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard_for_post') as mock_keyboard_post:
with patch('helper_bot.handlers.private.private_handlers.get_reply_keyboard') as mock_keyboard:
with patch('helper_bot.handlers.private.private_handlers.prepare_media_group_from_middlewares') as mock_prepare:
with patch('helper_bot.handlers.private.private_handlers.send_media_group_message_to_private_chat') as mock_send_group:
with patch('helper_bot.handlers.private.private_handlers.send_text_message') as mock_send_text:
with patch('helper_bot.handlers.private.private_handlers.messages.get_message') as mock_messages:
with patch('helper_bot.handlers.private.private_handlers.sleep'):
# Настройка моков для медиагруппы без подписи
mock_message.media_group_id = 'group_123'
mock_message.content_type = 'photo'
# Создаем мок альбома без подписи
album = [mock_message]
album[0].caption = None
mock_keyboard_post.return_value = Mock()
mock_keyboard.return_value = Mock()
mock_prepare.return_value = ['media1', 'media2']
mock_send_group.return_value = 123
mock_send_text.return_value = 456
mock_messages.return_value = "Медиагруппа отправлена!"
# Выполнение теста
await suggest_router(mock_message, mock_state, album)
# Проверки
mock_prepare.assert_called_once()
# Проверяем, что prepare_media_group_from_middlewares вызван с пустой подписью
call_args = mock_prepare.call_args
assert call_args.kwargs.get('post_caption', '') == ''
if __name__ == '__main__':
pytest.main([__file__, '-v'])