import asyncio from datetime import datetime from unittest.mock import AsyncMock, MagicMock import pytest from database.models import UserMessage from database.repositories.message_repository import MessageRepository class TestMessageRepository: """Тесты для MessageRepository.""" @pytest.fixture def mock_db_path(self): """Фикстура для пути к тестовой БД.""" return ":memory:" @pytest.fixture def message_repository(self, mock_db_path): """Фикстура для MessageRepository.""" return MessageRepository(mock_db_path) @pytest.fixture def sample_message(self): """Фикстура для тестового сообщения.""" return UserMessage( message_text="Тестовое сообщение", user_id=12345, telegram_message_id=67890, date=int(datetime.now().timestamp()), ) @pytest.fixture def sample_message_no_date(self): """Фикстура для тестового сообщения без даты.""" return UserMessage( message_text="Тестовое сообщение без даты", user_id=12345, telegram_message_id=67891, date=None, ) @pytest.mark.asyncio async def test_create_tables(self, message_repository): """Тест создания таблиц.""" # Мокаем _execute_query message_repository._execute_query = AsyncMock() await message_repository.create_tables() message_repository._execute_query.assert_called_once() call_args = message_repository._execute_query.call_args[0][0] assert "CREATE TABLE IF NOT EXISTS user_messages" in call_args assert "telegram_message_id INTEGER NOT NULL" in call_args assert "date INTEGER NOT NULL" in call_args assert ( "FOREIGN KEY (user_id) REFERENCES our_users (user_id) ON DELETE CASCADE" in call_args ) @pytest.mark.asyncio async def test_add_message_with_date(self, message_repository, sample_message): """Тест добавления сообщения с датой.""" # Мокаем _execute_query message_repository._execute_query = AsyncMock() await message_repository.add_message(sample_message) message_repository._execute_query.assert_called_once() call_args = message_repository._execute_query.call_args query = call_args[0][0] params = call_args[0][1] assert "INSERT INTO user_messages" in query assert "VALUES (?, ?, ?, ?)" in query assert params == ( sample_message.message_text, sample_message.user_id, sample_message.telegram_message_id, sample_message.date, ) @pytest.mark.asyncio async def test_add_message_without_date( self, message_repository, sample_message_no_date ): """Тест добавления сообщения без даты (должна генерироваться автоматически).""" # Мокаем _execute_query message_repository._execute_query = AsyncMock() await message_repository.add_message(sample_message_no_date) # Проверяем, что дата была установлена assert sample_message_no_date.date is not None assert isinstance(sample_message_no_date.date, int) assert sample_message_no_date.date > 0 message_repository._execute_query.assert_called_once() call_args = message_repository._execute_query.call_args params = call_args[0][1] assert params[3] == sample_message_no_date.date # date field @pytest.mark.asyncio async def test_add_message_logs_correctly(self, message_repository, sample_message): """Тест логирования при добавлении сообщения.""" # Мокаем _execute_query и logger message_repository._execute_query = AsyncMock() message_repository.logger = MagicMock() await message_repository.add_message(sample_message) message_repository.logger.info.assert_called_once() log_message = message_repository.logger.info.call_args[0][0] assert ( f"telegram_message_id={sample_message.telegram_message_id}" in log_message ) @pytest.mark.asyncio async def test_get_user_by_message_id_found(self, message_repository): """Тест получения пользователя по message_id (пользователь найден).""" message_id = 67890 expected_user_id = 12345 # Мокаем _execute_query_with_result message_repository._execute_query_with_result = AsyncMock( return_value=[[expected_user_id]] ) result = await message_repository.get_user_by_message_id(message_id) assert result == expected_user_id message_repository._execute_query_with_result.assert_called_once_with( "SELECT user_id FROM user_messages WHERE telegram_message_id = ?", (message_id,), ) @pytest.mark.asyncio async def test_get_user_by_message_id_not_found(self, message_repository): """Тест получения пользователя по message_id (пользователь не найден).""" message_id = 99999 # Мокаем _execute_query_with_result message_repository._execute_query_with_result = AsyncMock(return_value=[]) result = await message_repository.get_user_by_message_id(message_id) assert result is None message_repository._execute_query_with_result.assert_called_once_with( "SELECT user_id FROM user_messages WHERE telegram_message_id = ?", (message_id,), ) @pytest.mark.asyncio async def test_get_user_by_message_id_empty_result(self, message_repository): """Тест получения пользователя по message_id (пустой результат).""" message_id = 99999 # Мокаем _execute_query_with_result message_repository._execute_query_with_result = AsyncMock(return_value=[[]]) result = await message_repository.get_user_by_message_id(message_id) assert result is None @pytest.mark.asyncio async def test_add_message_handles_exception( self, message_repository, sample_message ): """Тест обработки исключений при добавлении сообщения.""" # Мокаем _execute_query для вызова исключения message_repository._execute_query = AsyncMock( side_effect=Exception("Database error") ) with pytest.raises(Exception, match="Database error"): await message_repository.add_message(sample_message) @pytest.mark.asyncio async def test_get_user_by_message_id_handles_exception(self, message_repository): """Тест обработки исключений при получении пользователя.""" # Мокаем _execute_query_with_result для вызова исключения message_repository._execute_query_with_result = AsyncMock( side_effect=Exception("Database error") ) with pytest.raises(Exception, match="Database error"): await message_repository.get_user_by_message_id(12345) @pytest.mark.asyncio async def test_add_message_with_zero_date(self, message_repository): """Тест добавления сообщения с датой равной 0 (должна генерироваться новая).""" message = UserMessage( message_text="Тестовое сообщение с нулевой датой", user_id=12345, telegram_message_id=67892, date=0, ) # Мокаем _execute_query message_repository._execute_query = AsyncMock() await message_repository.add_message(message) # Проверяем, что дата была изменена с 0 (теперь это происходит только если date is None) # В текущей реализации дата 0 считается валидной и не изменяется assert isinstance(message.date, int) assert message.date >= 0 message_repository._execute_query.assert_called_once() params = message_repository._execute_query.call_args[0][1] assert params[3] == message.date # date field if __name__ == "__main__": pytest.main([__file__])