import pytest from unittest.mock import Mock, AsyncMock, patch from aiogram import types from aiogram.fsm.context import FSMContext from helper_bot.handlers.admin.services import AdminService, User, BannedUser from helper_bot.handlers.admin.exceptions import ( UserNotFoundError, UserAlreadyBannedError, InvalidInputError ) class TestAdminService: """Тесты для AdminService""" def setup_method(self): """Настройка перед каждым тестом""" self.mock_db = Mock() self.admin_service = AdminService(self.mock_db) def test_get_last_users_success(self): """Тест успешного получения списка последних пользователей""" # Arrange # Формат данных: кортежи (full_name, user_id) как возвращает БД mock_users_data = [ ('User One', 1), # (full_name, user_id) ('User Two', 2) # (full_name, user_id) ] self.mock_db.get_last_users_from_db.return_value = mock_users_data # Act result = self.admin_service.get_last_users() # Assert assert len(result) == 2 assert result[0].user_id == 1 assert result[0].username == 'Неизвестно' # username не возвращается из БД assert result[0].full_name == 'User One' assert result[1].user_id == 2 assert result[1].username == 'Неизвестно' # username не возвращается из БД assert result[1].full_name == 'User Two' def test_get_user_by_username_success(self): """Тест успешного получения пользователя по username""" # Arrange user_id = 123 username = "test_user" full_name = "Test User" self.mock_db.get_user_id_by_username.return_value = user_id self.mock_db.get_full_name_by_id.return_value = full_name # Act result = self.admin_service.get_user_by_username(username) # Assert assert result is not None assert result.user_id == user_id assert result.username == username assert result.full_name == full_name def test_get_user_by_username_not_found(self): """Тест получения пользователя по несуществующему username""" # Arrange username = "nonexistent_user" self.mock_db.get_user_id_by_username.return_value = None # Act result = self.admin_service.get_user_by_username(username) # Assert assert result is None def test_get_user_by_id_success(self): """Тест успешного получения пользователя по ID""" # Arrange user_id = 123 user_info = {'username': 'test_user', 'full_name': 'Test User'} self.mock_db.get_user_info_by_id.return_value = user_info # Act result = self.admin_service.get_user_by_id(user_id) # Assert assert result is not None assert result.user_id == user_id assert result.username == 'test_user' assert result.full_name == 'Test User' def test_get_user_by_id_not_found(self): """Тест получения пользователя по несуществующему ID""" # Arrange user_id = 999 self.mock_db.get_user_info_by_id.return_value = None # Act result = self.admin_service.get_user_by_id(user_id) # Assert assert result is None def test_validate_user_input_success(self): """Тест успешной валидации ID пользователя""" # Act result = self.admin_service.validate_user_input("123") # Assert assert result == 123 def test_validate_user_input_invalid_number(self): """Тест валидации некорректного ID""" # Act & Assert with pytest.raises(InvalidInputError, match="ID пользователя должен быть числом"): self.admin_service.validate_user_input("abc") def test_validate_user_input_negative_number(self): """Тест валидации отрицательного ID""" # Act & Assert with pytest.raises(InvalidInputError, match="ID пользователя должен быть положительным числом"): self.admin_service.validate_user_input("-1") def test_validate_user_input_zero(self): """Тест валидации нулевого ID""" # Act & Assert with pytest.raises(InvalidInputError, match="ID пользователя должен быть положительным числом"): self.admin_service.validate_user_input("0") def test_ban_user_success(self): """Тест успешной блокировки пользователя""" # Arrange user_id = 123 username = "test_user" reason = "Test ban" ban_days = 7 self.mock_db.check_user_in_blacklist.return_value = False self.mock_db.set_user_blacklist.return_value = None # Act self.admin_service.ban_user(user_id, username, reason, ban_days) # Assert self.mock_db.check_user_in_blacklist.assert_called_once_with(user_id) self.mock_db.set_user_blacklist.assert_called_once() def test_ban_user_already_banned(self): """Тест попытки заблокировать уже заблокированного пользователя""" # Arrange user_id = 123 username = "test_user" reason = "Test ban" ban_days = 7 self.mock_db.check_user_in_blacklist.return_value = True # Act & Assert with pytest.raises(UserAlreadyBannedError, match=f"Пользователь {user_id} уже заблокирован"): self.admin_service.ban_user(user_id, username, reason, ban_days) def test_ban_user_permanent(self): """Тест постоянной блокировки пользователя""" # Arrange user_id = 123 username = "test_user" reason = "Permanent ban" ban_days = None self.mock_db.check_user_in_blacklist.return_value = False self.mock_db.set_user_blacklist.return_value = None # Act self.admin_service.ban_user(user_id, username, reason, ban_days) # Assert self.mock_db.set_user_blacklist.assert_called_once_with(user_id, username, reason, None) def test_unban_user_success(self): """Тест успешной разблокировки пользователя""" # Arrange user_id = 123 self.mock_db.delete_user_blacklist.return_value = None # Act self.admin_service.unban_user(user_id) # Assert self.mock_db.delete_user_blacklist.assert_called_once_with(user_id) class TestUser: """Тесты для модели User""" def test_user_creation(self): """Тест создания объекта User""" # Act user = User(user_id=123, username="test_user", full_name="Test User") # Assert assert user.user_id == 123 assert user.username == "test_user" assert user.full_name == "Test User" class TestBannedUser: """Тесты для модели BannedUser""" def test_banned_user_creation(self): """Тест создания объекта BannedUser""" # Act banned_user = BannedUser( user_id=123, username="test_user", reason="Test ban", unban_date="2025-01-01" ) # Assert assert banned_user.user_id == 123 assert banned_user.username == "test_user" assert banned_user.reason == "Test ban" assert banned_user.unban_date == "2025-01-01"