fix quality code
This commit is contained in:
@@ -3,8 +3,11 @@ from datetime import datetime
|
||||
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from helper_bot.handlers.callback.callback_handlers import (
|
||||
delete_voice_message, save_voice_message)
|
||||
delete_voice_message,
|
||||
save_voice_message,
|
||||
)
|
||||
from helper_bot.handlers.voice.constants import CALLBACK_DELETE, CALLBACK_SAVE
|
||||
|
||||
|
||||
@@ -21,6 +24,7 @@ def mock_call():
|
||||
call.answer = AsyncMock()
|
||||
return call
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_bot_db():
|
||||
"""Мок для базы данных"""
|
||||
@@ -29,20 +33,20 @@ def mock_bot_db():
|
||||
mock_db.delete_audio_moderate_record = AsyncMock()
|
||||
return mock_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_settings():
|
||||
"""Мок для настроек"""
|
||||
return {
|
||||
'Telegram': {
|
||||
'group_for_posts': 'test_group_id'
|
||||
}
|
||||
}
|
||||
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.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
|
||||
@@ -50,143 +54,205 @@ def mock_audio_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):
|
||||
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:
|
||||
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)
|
||||
|
||||
|
||||
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_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
|
||||
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)
|
||||
|
||||
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):
|
||||
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:
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
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")
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
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:
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
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_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)
|
||||
|
||||
|
||||
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)
|
||||
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):
|
||||
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)
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
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):
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
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_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)
|
||||
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):
|
||||
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:
|
||||
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.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)
|
||||
|
||||
|
||||
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
|
||||
@@ -195,46 +261,62 @@ class TestCallbackHandlersIntegration:
|
||||
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):
|
||||
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)
|
||||
|
||||
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):
|
||||
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.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:
|
||||
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.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)
|
||||
|
||||
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)
|
||||
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
|
||||
@@ -242,9 +324,11 @@ class TestCallbackHandlersIntegration:
|
||||
|
||||
class TestCallbackHandlersEdgeCases:
|
||||
"""Тесты граничных случаев для callback handlers"""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_save_voice_message_no_voice_attribute(self, mock_bot_db, mock_settings):
|
||||
async def test_save_voice_message_no_voice_attribute(
|
||||
self, mock_bot_db, mock_settings
|
||||
):
|
||||
"""Тест сохранения когда у сообщения нет voice атрибута"""
|
||||
call = Mock()
|
||||
call.message = Mock()
|
||||
@@ -253,26 +337,36 @@ class TestCallbackHandlersEdgeCases:
|
||||
call.bot = Mock()
|
||||
call.bot.delete_message = AsyncMock()
|
||||
call.answer = AsyncMock()
|
||||
|
||||
with patch('helper_bot.handlers.callback.callback_handlers.AudioFileService'):
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
async def test_delete_voice_message_with_different_message_id(
|
||||
self, mock_bot_db, mock_settings
|
||||
):
|
||||
"""Тест удаления с другим message_id"""
|
||||
call = Mock()
|
||||
call.message = Mock()
|
||||
@@ -280,16 +374,15 @@ class TestCallbackHandlersEdgeCases:
|
||||
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
|
||||
chat_id="test_group_id", message_id=99999
|
||||
)
|
||||
mock_bot_db.delete_audio_moderate_record.assert_called_once_with(99999)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
|
||||
Reference in New Issue
Block a user