666 lines
26 KiB
Python
666 lines
26 KiB
Python
import time
|
||
from datetime import datetime
|
||
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||
|
||
import pytest
|
||
|
||
from helper_bot.handlers.callback.callback_handlers import (
|
||
change_page,
|
||
delete_voice_message,
|
||
process_ban_user,
|
||
process_unlock_user,
|
||
return_to_main_menu,
|
||
save_voice_message,
|
||
)
|
||
from helper_bot.handlers.voice.constants import CALLBACK_DELETE, CALLBACK_SAVE
|
||
|
||
|
||
@pytest.fixture
|
||
def mock_call():
|
||
"""Мок для CallbackQuery"""
|
||
call = Mock()
|
||
call.message = Mock()
|
||
call.message.message_id = 12345
|
||
call.message.voice = Mock()
|
||
call.message.voice.file_id = "test_file_id_123"
|
||
call.bot = Mock()
|
||
call.bot.delete_message = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
return call
|
||
|
||
|
||
@pytest.fixture
|
||
def mock_bot_db():
|
||
"""Мок для базы данных"""
|
||
mock_db = Mock()
|
||
mock_db.get_user_id_by_message_id_for_voice_bot = AsyncMock(return_value=67890)
|
||
mock_db.delete_audio_moderate_record = AsyncMock()
|
||
return mock_db
|
||
|
||
|
||
@pytest.fixture
|
||
def mock_settings():
|
||
"""Мок для настроек"""
|
||
return {"Telegram": {"group_for_posts": "test_group_id"}}
|
||
|
||
|
||
@pytest.fixture
|
||
def mock_audio_service():
|
||
"""Мок для AudioFileService"""
|
||
mock_service = Mock()
|
||
mock_service.generate_file_name = AsyncMock(
|
||
return_value="message_from_67890_number_1"
|
||
)
|
||
mock_service.save_audio_file = AsyncMock()
|
||
mock_service.download_and_save_audio = AsyncMock()
|
||
return mock_service
|
||
|
||
|
||
class TestSaveVoiceMessage:
|
||
"""Тесты для функции save_voice_message"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_success(
|
||
self, mock_call, mock_bot_db, mock_settings, mock_audio_service
|
||
):
|
||
"""Тест успешного сохранения голосового сообщения"""
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service_class.return_value = mock_audio_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем, что все методы вызваны
|
||
mock_bot_db.get_user_id_by_message_id_for_voice_bot.assert_called_once_with(
|
||
12345
|
||
)
|
||
mock_audio_service.generate_file_name.assert_called_once_with(67890)
|
||
mock_audio_service.save_audio_file.assert_called_once()
|
||
mock_audio_service.download_and_save_audio.assert_called_once_with(
|
||
mock_call.bot, mock_call.message, "message_from_67890_number_1"
|
||
)
|
||
|
||
# Проверяем удаление сообщения из чата
|
||
mock_call.bot.delete_message.assert_called_once_with(
|
||
chat_id="test_group_id", message_id=12345
|
||
)
|
||
|
||
# Проверяем удаление записи из audio_moderate
|
||
mock_bot_db.delete_audio_moderate_record.assert_called_once_with(12345)
|
||
|
||
# Проверяем ответ пользователю
|
||
mock_call.answer.assert_called_once_with(text="Сохранено!", cache_time=3)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_with_correct_parameters(
|
||
self, mock_call, mock_bot_db, mock_settings, mock_audio_service
|
||
):
|
||
"""Тест сохранения с правильными параметрами"""
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service_class.return_value = mock_audio_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем параметры save_audio_file
|
||
save_call_args = mock_audio_service.save_audio_file.call_args
|
||
assert save_call_args[0][0] == "message_from_67890_number_1" # file_name
|
||
assert save_call_args[0][1] == 67890 # user_id
|
||
assert isinstance(save_call_args[0][2], datetime) # date_added
|
||
assert save_call_args[0][3] == "test_file_id_123" # file_id
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_exception_handling(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест обработки исключений при сохранении"""
|
||
mock_bot_db.get_user_id_by_message_id_for_voice_bot.side_effect = Exception(
|
||
"Database error"
|
||
)
|
||
|
||
await save_voice_message(mock_call, bot_db=mock_bot_db, settings=mock_settings)
|
||
|
||
# Проверяем, что при ошибке отправляется соответствующий ответ
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при сохранении!", cache_time=3
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_audio_service_exception(
|
||
self, mock_call, mock_bot_db, mock_settings, mock_audio_service
|
||
):
|
||
"""Тест обработки исключений в AudioFileService"""
|
||
mock_audio_service.save_audio_file.side_effect = Exception("Save error")
|
||
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service_class.return_value = mock_audio_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем, что при ошибке отправляется соответствующий ответ
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при сохранении!", cache_time=3
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_download_exception(
|
||
self, mock_call, mock_bot_db, mock_settings, mock_audio_service
|
||
):
|
||
"""Тест обработки исключений при скачивании файла"""
|
||
mock_audio_service.download_and_save_audio.side_effect = Exception(
|
||
"Download error"
|
||
)
|
||
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service_class.return_value = mock_audio_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем, что при ошибке отправляется соответствующий ответ
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при сохранении!", cache_time=3
|
||
)
|
||
|
||
|
||
class TestDeleteVoiceMessage:
|
||
"""Тесты для функции delete_voice_message"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_delete_voice_message_success(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест успешного удаления голосового сообщения"""
|
||
await delete_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем удаление сообщения из чата
|
||
mock_call.bot.delete_message.assert_called_once_with(
|
||
chat_id="test_group_id", message_id=12345
|
||
)
|
||
|
||
# Проверяем удаление записи из audio_moderate
|
||
mock_bot_db.delete_audio_moderate_record.assert_called_once_with(12345)
|
||
|
||
# Проверяем ответ пользователю
|
||
mock_call.answer.assert_called_once_with(text="Удалено!", cache_time=3)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_delete_voice_message_exception_handling(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест обработки исключений при удалении"""
|
||
mock_call.bot.delete_message.side_effect = Exception("Delete error")
|
||
|
||
await delete_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем, что при ошибке отправляется соответствующий ответ
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при удалении!", cache_time=3
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_delete_voice_message_database_exception(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест обработки исключений в базе данных при удалении"""
|
||
mock_bot_db.delete_audio_moderate_record.side_effect = Exception(
|
||
"Database error"
|
||
)
|
||
|
||
await delete_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем, что при ошибке отправляется соответствующий ответ
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при удалении!", cache_time=3
|
||
)
|
||
|
||
|
||
class TestCallbackHandlersIntegration:
|
||
"""Интеграционные тесты для callback handlers"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_full_workflow(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест полного рабочего процесса сохранения"""
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service = Mock()
|
||
mock_service.generate_file_name = AsyncMock(
|
||
return_value="message_from_67890_number_1"
|
||
)
|
||
mock_service.save_audio_file = AsyncMock()
|
||
mock_service.download_and_save_audio = AsyncMock()
|
||
mock_service_class.return_value = mock_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем последовательность вызовов
|
||
assert mock_bot_db.get_user_id_by_message_id_for_voice_bot.called
|
||
assert mock_service.generate_file_name.called
|
||
assert mock_service.save_audio_file.called
|
||
assert mock_service.download_and_save_audio.called
|
||
assert mock_call.bot.delete_message.called
|
||
assert mock_bot_db.delete_audio_moderate_record.called
|
||
assert mock_call.answer.called
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_delete_voice_message_full_workflow(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест полного рабочего процесса удаления"""
|
||
await delete_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Проверяем последовательность вызовов
|
||
assert mock_call.bot.delete_message.called
|
||
assert mock_bot_db.delete_audio_moderate_record.called
|
||
assert mock_call.answer.called
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_audio_moderate_cleanup_consistency(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест консистентности очистки audio_moderate"""
|
||
# Тестируем, что в обоих случаях (сохранение и удаление)
|
||
# вызывается delete_audio_moderate_record
|
||
|
||
# Создаем отдельные моки для каждого теста
|
||
mock_bot_db_save = Mock()
|
||
mock_bot_db_save.get_user_id_by_message_id_for_voice_bot = AsyncMock(
|
||
return_value=67890
|
||
)
|
||
mock_bot_db_save.delete_audio_moderate_record = AsyncMock()
|
||
|
||
mock_bot_db_delete = Mock()
|
||
mock_bot_db_delete.delete_audio_moderate_record = AsyncMock()
|
||
|
||
# Тест для сохранения
|
||
with patch(
|
||
"helper_bot.handlers.callback.callback_handlers.AudioFileService"
|
||
) as mock_service_class:
|
||
mock_service = Mock()
|
||
mock_service.generate_file_name = AsyncMock(
|
||
return_value="message_from_67890_number_1"
|
||
)
|
||
mock_service.save_audio_file = AsyncMock()
|
||
mock_service.download_and_save_audio = AsyncMock()
|
||
mock_service_class.return_value = mock_service
|
||
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db_save, settings=mock_settings
|
||
)
|
||
save_calls = mock_bot_db_save.delete_audio_moderate_record.call_count
|
||
|
||
# Тест для удаления
|
||
await delete_voice_message(
|
||
mock_call, bot_db=mock_bot_db_delete, settings=mock_settings
|
||
)
|
||
delete_calls = mock_bot_db_delete.delete_audio_moderate_record.call_count
|
||
|
||
# Проверяем, что в обоих случаях вызывается очистка
|
||
assert save_calls == 1
|
||
assert delete_calls == 1
|
||
|
||
|
||
class TestCallbackHandlersEdgeCases:
|
||
"""Тесты граничных случаев для callback handlers"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_no_voice_attribute(
|
||
self, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест сохранения когда у сообщения нет voice атрибута"""
|
||
call = Mock()
|
||
call.message = Mock()
|
||
call.message.message_id = 12345
|
||
call.message.voice = None # Нет голосового сообщения
|
||
call.bot = Mock()
|
||
call.bot.delete_message = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
|
||
with patch("helper_bot.handlers.callback.callback_handlers.AudioFileService"):
|
||
await save_voice_message(call, bot_db=mock_bot_db, settings=mock_settings)
|
||
|
||
# Должна быть ошибка
|
||
call.answer.assert_called_once_with(
|
||
text="Ошибка при сохранении!", cache_time=3
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_save_voice_message_user_not_found(
|
||
self, mock_call, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест сохранения когда пользователь не найден"""
|
||
mock_bot_db.get_user_id_by_message_id_for_voice_bot.return_value = None
|
||
|
||
with patch("helper_bot.handlers.callback.callback_handlers.AudioFileService"):
|
||
await save_voice_message(
|
||
mock_call, bot_db=mock_bot_db, settings=mock_settings
|
||
)
|
||
|
||
# Должна быть ошибка
|
||
mock_call.answer.assert_called_once_with(
|
||
text="Ошибка при сохранении!", cache_time=3
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_delete_voice_message_with_different_message_id(
|
||
self, mock_bot_db, mock_settings
|
||
):
|
||
"""Тест удаления с другим message_id"""
|
||
call = Mock()
|
||
call.message = Mock()
|
||
call.message.message_id = 99999 # Другой ID
|
||
call.bot = Mock()
|
||
call.bot.delete_message = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
|
||
await delete_voice_message(call, bot_db=mock_bot_db, settings=mock_settings)
|
||
|
||
# Проверяем, что используется правильный message_id
|
||
call.bot.delete_message.assert_called_once_with(
|
||
chat_id="test_group_id", message_id=99999
|
||
)
|
||
mock_bot_db.delete_audio_moderate_record.assert_called_once_with(99999)
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestReturnToMainMenu:
|
||
"""Тесты для return_to_main_menu."""
|
||
|
||
@pytest.fixture
|
||
def mock_call(self):
|
||
call = Mock()
|
||
call.message = Mock()
|
||
call.message.message_id = 1
|
||
call.message.from_user = Mock()
|
||
call.message.from_user.id = 123
|
||
call.message.delete = AsyncMock()
|
||
call.message.answer = AsyncMock()
|
||
return call
|
||
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_reply_keyboard_admin")
|
||
async def test_return_to_main_menu_deletes_and_answers(
|
||
self, mock_keyboard, mock_call
|
||
):
|
||
"""return_to_main_menu удаляет сообщение и отправляет приветствие."""
|
||
mock_keyboard.return_value = MagicMock()
|
||
|
||
await return_to_main_menu(mock_call)
|
||
|
||
mock_call.message.delete.assert_called_once()
|
||
mock_call.message.answer.assert_called_once()
|
||
assert (
|
||
"админк" in mock_call.message.answer.call_args[0][0].lower()
|
||
or "добро" in mock_call.message.answer.call_args[0][0].lower()
|
||
)
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestChangePage:
|
||
"""Тесты для change_page."""
|
||
|
||
@pytest.fixture
|
||
def mock_bot_db_for_page(self):
|
||
"""Мок БД для change_page."""
|
||
db = Mock()
|
||
db.get_last_users = AsyncMock(return_value=[("U1", 1), ("U2", 2)])
|
||
return db
|
||
|
||
@pytest.fixture
|
||
def mock_call_list_users(self):
|
||
call = Mock()
|
||
call.data = "page_2"
|
||
call.message = Mock()
|
||
call.message.text = "Список пользователей которые последними обращались к боту"
|
||
call.message.chat = Mock()
|
||
call.message.chat.id = 1
|
||
call.message.message_id = 10
|
||
call.bot = Mock()
|
||
call.bot.edit_message_reply_markup = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
return call
|
||
|
||
@pytest.fixture
|
||
def mock_bot_db(self):
|
||
db = Mock()
|
||
db.get_last_users = AsyncMock(return_value=[("U1", 1), ("U2", 2)])
|
||
return db
|
||
|
||
@patch(
|
||
"helper_bot.handlers.callback.callback_handlers.create_keyboard_with_pagination"
|
||
)
|
||
async def test_change_page_list_users_edits_markup(
|
||
self, mock_keyboard, mock_call_list_users, mock_bot_db_for_page
|
||
):
|
||
"""change_page для списка пользователей редактирует reply_markup."""
|
||
mock_keyboard.return_value = MagicMock()
|
||
|
||
await change_page(mock_call_list_users, bot_db=mock_bot_db_for_page)
|
||
|
||
mock_bot_db_for_page.get_last_users.assert_awaited_once_with(30)
|
||
mock_call_list_users.bot.edit_message_reply_markup.assert_awaited_once()
|
||
|
||
@patch(
|
||
"helper_bot.handlers.callback.callback_handlers.get_banned_users_buttons",
|
||
new_callable=AsyncMock,
|
||
)
|
||
@patch(
|
||
"helper_bot.handlers.callback.callback_handlers.get_banned_users_list",
|
||
new_callable=AsyncMock,
|
||
)
|
||
@patch(
|
||
"helper_bot.handlers.callback.callback_handlers.create_keyboard_with_pagination"
|
||
)
|
||
async def test_change_page_banned_list_edits_text_and_markup(
|
||
self, mock_keyboard, mock_get_list, mock_get_buttons, mock_bot_db_for_page
|
||
):
|
||
"""change_page для списка забаненных редактирует текст и клавиатуру."""
|
||
mock_get_list.return_value = "Текст страницы"
|
||
mock_get_buttons.return_value = []
|
||
call = Mock()
|
||
call.data = "page_1"
|
||
call.message = Mock()
|
||
call.message.text = "Заблокированные пользователи"
|
||
call.message.chat = Mock()
|
||
call.message.chat.id = 1
|
||
call.message.message_id = 10
|
||
call.bot = Mock()
|
||
call.bot.edit_message_text = AsyncMock()
|
||
call.bot.edit_message_reply_markup = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
mock_keyboard.return_value = MagicMock()
|
||
|
||
await change_page(call, bot_db=mock_bot_db_for_page)
|
||
|
||
mock_get_list.assert_awaited_once()
|
||
mock_get_buttons.assert_awaited_once()
|
||
call.bot.edit_message_text.assert_awaited_once()
|
||
call.bot.edit_message_reply_markup.assert_awaited_once()
|
||
|
||
async def test_change_page_invalid_page_number_answers_error(
|
||
self, mock_bot_db_for_page
|
||
):
|
||
"""change_page при некорректном номере страницы отвечает ошибкой."""
|
||
call = Mock()
|
||
call.data = "page_abc"
|
||
call.answer = AsyncMock()
|
||
|
||
await change_page(call, bot_db=mock_bot_db_for_page)
|
||
|
||
call.answer.assert_awaited_once_with(
|
||
text="Ошибка: некорректный номер страницы", show_alert=True, cache_time=3
|
||
)
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestProcessBanUser:
|
||
"""Тесты для process_ban_user."""
|
||
|
||
@pytest.fixture
|
||
def mock_bot_db_ban(self):
|
||
"""Мок БД для process_ban_user."""
|
||
db = Mock()
|
||
db.get_full_name_by_id = AsyncMock(return_value="Full Name")
|
||
return db
|
||
|
||
@pytest.fixture
|
||
def mock_call(self):
|
||
call = Mock()
|
||
call.data = "ban_123456"
|
||
call.from_user = Mock()
|
||
call.message = Mock()
|
||
call.message.answer = AsyncMock()
|
||
call.answer = AsyncMock()
|
||
return call
|
||
|
||
@pytest.fixture
|
||
def mock_state(self):
|
||
state = Mock()
|
||
state.update_data = AsyncMock()
|
||
state.set_state = AsyncMock()
|
||
return state
|
||
|
||
@patch(
|
||
"helper_bot.handlers.callback.callback_handlers.create_keyboard_for_ban_reason"
|
||
)
|
||
@patch("helper_bot.handlers.callback.callback_handlers.format_user_info")
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_ban_service")
|
||
async def test_process_ban_user_success_sets_state_await_details(
|
||
self,
|
||
mock_get_ban,
|
||
mock_format,
|
||
mock_keyboard,
|
||
mock_call,
|
||
mock_state,
|
||
mock_bot_db_ban,
|
||
):
|
||
"""process_ban_user при успехе переводит в AWAIT_BAN_DETAILS."""
|
||
mock_ban = Mock()
|
||
mock_ban.ban_user = AsyncMock(return_value="username")
|
||
mock_get_ban.return_value = mock_ban
|
||
mock_format.return_value = "User info"
|
||
mock_keyboard.return_value = MagicMock()
|
||
|
||
await process_ban_user(mock_call, mock_state, bot_db=mock_bot_db_ban)
|
||
|
||
mock_state.update_data.assert_awaited_once()
|
||
mock_state.set_state.assert_awaited_once_with("AWAIT_BAN_DETAILS")
|
||
mock_call.message.answer.assert_awaited_once()
|
||
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_reply_keyboard_admin")
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_ban_service")
|
||
async def test_process_ban_user_not_found_returns_to_admin(
|
||
self, mock_get_ban, mock_keyboard, mock_call, mock_state, mock_bot_db_ban
|
||
):
|
||
"""process_ban_user при UserNotFoundError возвращает в админ-меню."""
|
||
from helper_bot.handlers.callback.exceptions import UserNotFoundError
|
||
|
||
mock_ban = Mock()
|
||
mock_ban.ban_user = AsyncMock(side_effect=UserNotFoundError("not found"))
|
||
mock_get_ban.return_value = mock_ban
|
||
mock_keyboard.return_value = MagicMock()
|
||
|
||
await process_ban_user(mock_call, mock_state, bot_db=mock_bot_db_ban)
|
||
|
||
mock_call.message.answer.assert_awaited_once()
|
||
mock_state.set_state.assert_awaited_once_with("ADMIN")
|
||
|
||
async def test_process_ban_user_invalid_user_id_answers_error(
|
||
self, mock_call, mock_state, mock_bot_db_ban
|
||
):
|
||
"""process_ban_user при некорректном user_id отвечает ошибкой."""
|
||
mock_call.data = "ban_abc"
|
||
|
||
await process_ban_user(mock_call, mock_state, bot_db=mock_bot_db_ban)
|
||
|
||
mock_call.answer.assert_awaited_once_with(
|
||
text="Ошибка: некорректный ID пользователя", show_alert=True, cache_time=3
|
||
)
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestProcessUnlockUser:
|
||
"""Тесты для process_unlock_user."""
|
||
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_ban_service")
|
||
async def test_process_unlock_user_success_answers_unlocked(self, mock_get_ban):
|
||
"""process_unlock_user при успехе отвечает сообщением о разблокировке."""
|
||
call = Mock()
|
||
call.data = "unlock_123"
|
||
call.answer = AsyncMock()
|
||
mock_ban = Mock()
|
||
mock_ban.unlock_user = AsyncMock(return_value="username")
|
||
mock_get_ban.return_value = mock_ban
|
||
|
||
await process_unlock_user(call)
|
||
|
||
mock_ban.unlock_user.assert_awaited_once_with("123")
|
||
call.answer.assert_awaited_once()
|
||
assert (
|
||
"username" in call.answer.call_args[0][0]
|
||
or "разблокирован" in call.answer.call_args[0][0].lower()
|
||
)
|
||
|
||
@patch("helper_bot.handlers.callback.callback_handlers.get_ban_service")
|
||
async def test_process_unlock_user_not_found_answers_error(self, mock_get_ban):
|
||
"""process_unlock_user при UserNotFoundError отвечает что пользователь не найден."""
|
||
from helper_bot.handlers.callback.exceptions import UserNotFoundError
|
||
|
||
call = Mock()
|
||
call.data = "unlock_999"
|
||
call.answer = AsyncMock()
|
||
mock_ban = Mock()
|
||
mock_ban.unlock_user = AsyncMock(side_effect=UserNotFoundError("not found"))
|
||
mock_get_ban.return_value = mock_ban
|
||
|
||
await process_unlock_user(call)
|
||
|
||
call.answer.assert_awaited_once_with(
|
||
text="Пользователь не найден в базе", show_alert=True, cache_time=3
|
||
)
|
||
|
||
async def test_process_unlock_user_invalid_user_id_answers_error(self):
|
||
"""process_unlock_user при некорректном user_id отвечает ошибкой."""
|
||
call = Mock()
|
||
call.data = "unlock_abc"
|
||
call.answer = AsyncMock()
|
||
|
||
await process_unlock_user(call)
|
||
|
||
call.answer.assert_awaited_once_with(
|
||
text="Ошибка: некорректный ID пользователя", show_alert=True, cache_time=3
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
pytest.main([__file__])
|