Files
telegram-helper-bot/tests/test_utils.py
Andrey 3d6b4353f9
All checks were successful
CI pipeline / Test & Code Quality (push) Successful in 34s
Refactor imports across multiple files to improve code organization and readability.
2026-02-28 23:24:25 +03:00

876 lines
36 KiB
Python
Raw 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 os
from datetime import datetime
from unittest.mock import AsyncMock, Mock, patch
import pytest
import helper_bot.utils.messages as messages # Import for patching constants
from database.async_db import AsyncBotDB
from helper_bot.utils.base_dependency_factory import (
BaseDependencyFactory,
get_global_instance,
)
from helper_bot.utils.helper_func import (
add_days_to_date,
add_in_db_media,
add_in_db_media_mediagroup,
check_access,
check_user_emoji,
check_username_and_full_name,
delete_user_blacklist,
determine_anonymity,
download_file,
get_banned_users_buttons,
get_banned_users_list,
get_first_name,
get_random_emoji,
get_text_message,
prepare_media_group_from_middlewares,
safe_html_escape,
send_audio_message,
send_media_group_message_to_private_chat,
send_media_group_to_channel,
send_photo_message,
send_text_message,
send_video_message,
send_video_note_message,
send_voice_message,
update_user_info,
)
from helper_bot.utils.messages import get_message
class TestHelperFunctions:
"""Тесты для вспомогательных функций"""
@pytest.fixture
def mock_message(self):
"""Создает мок сообщения для тестирования"""
message = Mock()
message.from_user = Mock()
message.from_user.first_name = "Test"
message.from_user.full_name = "Test User"
message.from_user.username = "testuser"
return message
def test_get_first_name(self, mock_message):
"""Тест функции получения имени пользователя"""
# Тест с обычным именем
result = get_first_name(mock_message)
assert result == "Test"
# Тест с пустым именем - функция get_first_name не обрабатывает None
# поэтому этот тест будет падать, что ожидаемо
mock_message.from_user.first_name = None
try:
result = get_first_name(mock_message)
assert False, "Ожидалась ошибка при None first_name"
except AttributeError:
pass # Ожидаемое поведение
def test_get_text_message(self, mock_message):
"""Тест функции обработки текста сообщения"""
# Тест с обычным текстом (legacy - определяется по тексту)
text = "Привет, это тестовое сообщение"
result = get_text_message(text, "Test", "testuser")
assert "Test" in result
assert "testuser" in result
assert "тестовое сообщение" in result
assert "Автор поста" in result
# Тест с пустым текстом
result = get_text_message("", "Test", "testuser")
assert "Test" in result
assert "testuser" in result
# Тест с текстом без специальных слов
text = "Обычный текст без специальных слов"
result = get_text_message(text, "Test", "testuser")
assert "Test" in result
assert "testuser" in result
assert "Обычный текст без специальных слов" in result
def test_get_text_message_with_is_anonymous_true(self, mock_message):
"""Тест функции get_text_message с is_anonymous=True"""
text = "Тестовый пост"
result = get_text_message(text, "Test", "testuser", is_anonymous=True)
assert "Тестовый пост" in result
assert "Пост опубликован анонимно" in result
assert "Автор поста" not in result
def test_get_text_message_with_is_anonymous_false(self, mock_message):
"""Тест функции get_text_message с is_anonymous=False"""
text = "Тестовый пост"
result = get_text_message(text, "Test", "testuser", is_anonymous=False)
assert "Тестовый пост" in result
assert "Автор поста" in result
assert "Test" in result
assert "testuser" in result
assert "Пост опубликован анонимно" not in result
def test_get_text_message_with_is_anonymous_none_legacy(self, mock_message):
"""Тест функции get_text_message с is_anonymous=None (legacy - определяется по тексту)"""
# Тест с "анон" в тексте
text = "Тестовый пост анон"
result = get_text_message(text, "Test", "testuser", is_anonymous=None)
assert "Тестовый пост анон" in result
assert "Пост опубликован анонимно" in result
# Тест с "неанон" в тексте
text = "Тестовый пост неанон"
result = get_text_message(text, "Test", "testuser", is_anonymous=None)
assert "Тестовый пост неанон" in result
assert "Автор поста" in result
# Тест с "не анон" в тексте
text = "Тестовый пост не анон"
result = get_text_message(text, "Test", "testuser", is_anonymous=None)
assert "Автор поста" in result
def test_get_text_message_with_username_none(self, mock_message):
"""Тест функции get_text_message без username"""
text = "Тестовый пост"
result = get_text_message(text, "Test", None, is_anonymous=False)
assert "Test" in result
assert "(Ник не указан)" in result
assert "@" not in result
def test_determine_anonymity_with_anon(self):
"""Тест функции determine_anonymity с 'анон' в тексте"""
assert determine_anonymity("Этот пост анон") is True
assert determine_anonymity("анон") is True
assert determine_anonymity("АНОН") is True # Проверка регистра
assert determine_anonymity("пост анонимный анон") is True
def test_determine_anonymity_with_neanon(self):
"""Тест функции determine_anonymity с 'неанон' в тексте"""
assert determine_anonymity("Этот пост неанон") is False
assert determine_anonymity("неанон") is False
assert determine_anonymity("НЕАНОН") is False # Проверка регистра
assert determine_anonymity("пост неанон") is False
def test_determine_anonymity_with_ne_anon(self):
"""Тест функции determine_anonymity с 'не анон' в тексте"""
assert determine_anonymity("Этот пост не анон") is False
assert determine_anonymity("не анон") is False
assert determine_anonymity("НЕ АНОН") is False # Проверка регистра
assert determine_anonymity("пост не анон") is False
def test_determine_anonymity_priority_neanon_over_anon(self):
"""Тест приоритета 'неанон' над 'анон'"""
# Если есть и "анон" и "неанон", должен вернуть False
assert determine_anonymity("анон неанон") is False
assert determine_anonymity("неанон анон") is False
assert determine_anonymity("не анон анон") is False
def test_determine_anonymity_without_keywords(self):
"""Тест функции determine_anonymity без ключевых слов"""
assert determine_anonymity("Обычный текст") is False
assert determine_anonymity("") is False
assert determine_anonymity("Пост без специальных слов") is False
def test_determine_anonymity_with_none(self):
"""Тест функции determine_anonymity с None"""
assert determine_anonymity(None) is False
def test_determine_anonymity_with_empty_string(self):
"""Тест функции determine_anonymity с пустой строкой"""
assert determine_anonymity("") is False
assert determine_anonymity(" ") is False # Только пробелы
@pytest.mark.asyncio
async def test_check_username_and_full_name(self):
"""Тест функции проверки изменений username и full_name"""
# Создаем мок базы данных
mock_db = Mock(spec=AsyncBotDB)
mock_db.get_username = AsyncMock(return_value="olduser")
mock_db.get_full_name_by_id = AsyncMock(return_value="Old User")
# Тест с измененными данными
result = await check_username_and_full_name(
123456, "newuser", "New User", mock_db
)
assert result is True
# Тест с неизмененными данными
result = await check_username_and_full_name(
123456, "olduser", "Old User", mock_db
)
assert result is False
# Тест с частично измененными данными
result = await check_username_and_full_name(
123456, "olduser", "New User", mock_db
)
assert result is True
result = await check_username_and_full_name(
123456, "newuser", "Old User", mock_db
)
assert result is True
class TestSafeHtmlEscape:
"""Тесты для функции безопасного экранирования HTML"""
def test_safe_html_escape_normal_text(self):
"""Тест экранирования обычного текста"""
result = safe_html_escape("Hello World")
assert result == "Hello World"
def test_safe_html_escape_html_tags(self):
"""Тест экранирования HTML тегов"""
result = safe_html_escape("<script>alert('xss')</script>")
assert result == "&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;"
def test_safe_html_escape_special_chars(self):
"""Тест экранирования специальных символов"""
result = safe_html_escape("& < > \" '")
assert result == "&amp; &lt; &gt; &quot; &#x27;"
def test_safe_html_escape_none_input(self):
"""Тест экранирования None значения"""
result = safe_html_escape(None)
assert result == ""
def test_safe_html_escape_empty_string(self):
"""Тест экранирования пустой строки"""
result = safe_html_escape("")
assert result == ""
def test_safe_html_escape_non_string_input(self):
"""Тест экранирования нестрокового ввода"""
result = safe_html_escape(123)
assert result == "123"
class TestMessages:
"""Тесты для системы сообщений"""
def test_get_message(self):
"""Тест функции получения сообщений"""
# Тест с существующим ключом
result = get_message("Test", "HELLO_MESSAGE")
assert isinstance(result, str)
assert len(result) > 0
# Тест с несуществующим ключом
try:
result = get_message("Test", "NON_EXISTENT_KEY")
assert False, "Ожидалась ошибка KeyError"
except KeyError:
pass # Ожидаемое поведение
# Тест с пустым именем
result = get_message("", "HELLO_MESSAGE")
assert isinstance(result, str)
assert len(result) > 0
# Тест с None именем - ожидаем ошибку
try:
result = get_message(None, "HELLO_MESSAGE")
assert False, "Ожидалась ошибка TypeError"
except TypeError:
pass # Ожидаемое поведение
def test_get_message_all_types(self):
"""Тест всех типов сообщений"""
# Patch the constants dictionary to include 'SUGGEST_NEWS_2' for testing purposes
with patch.dict(messages.constants, {"SUGGEST_NEWS_2": "Test message 2"}):
message_types = [
"HELLO_MESSAGE",
"SUGGEST_NEWS",
"SUGGEST_NEWS_2",
"BYE_MESSAGE",
"SUCCESS_SEND_MESSAGE",
"CONNECT_WITH_ADMIN",
"QUESTION",
]
for msg_type in message_types:
result = get_message("Test", msg_type)
assert isinstance(result, str)
assert len(result) > 0
class TestBaseDependencyFactory:
"""Тесты для фабрики зависимостей"""
def test_singleton_pattern(self):
"""Тест паттерна синглтон"""
# Сбрасываем глобальный экземпляр
import helper_bot.utils.base_dependency_factory
helper_bot.utils.base_dependency_factory._global_instance = None
# Получаем два экземпляра
instance1 = get_global_instance()
instance2 = get_global_instance()
# Проверяем, что это один и тот же объект
assert instance1 is instance2
assert id(instance1) == id(instance2)
def test_factory_initialization_with_mock_config(self):
"""Тест инициализации фабрики с мок конфигурацией"""
# With os.getenv mocked in tests/mocks.py, BaseDependencyFactory can be directly tested
factory = BaseDependencyFactory()
assert factory.settings is not None
assert factory.database is not None
def test_get_settings_method(self):
"""Тест метода get_settings"""
# With os.getenv mocked, settings can be directly accessed and verified
factory = BaseDependencyFactory()
settings = factory.get_settings()
assert settings["Telegram"]["bot_token"] == "test_token_123"
assert settings["Settings"]["logs"] is True
def test_get_db_method(self):
"""Тест метода get_db"""
# No need for configparser patch, os.getenv is already mocked globally
factory = BaseDependencyFactory()
db = factory.get_db()
assert db is not None
assert db == factory.database
class TestDatabaseIntegration:
"""Тесты интеграции с базой данных"""
def test_database_connection(self):
"""Тест подключения к базе данных"""
# No need for configparser patch, os.getenv is already mocked globally
factory = BaseDependencyFactory()
# Проверяем, что база данных была создана
# (mock_db is already a Mock object from tests/mocks.py)
# So, we just check if it's the correct mock instance
assert factory.database is not None
# Проверяем, что get_db возвращает тот же экземпляр
db1 = factory.get_db()
db2 = factory.get_db()
assert db1 is db2
class TestConfigurationHandling:
"""Тесты обработки конфигурации"""
def test_boolean_config_values(self):
"""Тест обработки булевых значений в конфигурации"""
# Now that os.getenv is mocked, we can directly test
factory = BaseDependencyFactory()
settings = factory.get_settings()
assert settings["Settings"]["logs"] is True
assert settings["Settings"]["test"] is False
def test_string_config_values(self):
"""Тест обработки строковых значений в конфигурации"""
# Now that os.getenv is mocked, we can directly test
factory = BaseDependencyFactory()
settings = factory.get_settings()
assert settings["Telegram"]["bot_token"] == "test_token_123"
assert settings["Telegram"]["main_public"] == "@test"
class TestDownloadFile:
"""Тесты для функции скачивания файлов"""
@pytest.mark.asyncio
async def test_download_file_success(self):
"""Тест успешного скачивания файла"""
mock_message = Mock()
mock_message.bot = AsyncMock()
# Мокаем get_file
mock_file = Mock()
mock_file.file_path = "photos/file_123.jpg"
mock_message.bot.get_file.return_value = mock_file
# Мокаем download_file
mock_message.bot.download_file = AsyncMock()
# Мокаем os.makedirs и другие зависимости
with patch("os.makedirs") as mock_makedirs:
with patch("os.path.join", return_value="files/photos/file_123.jpg"):
with patch("os.path.exists", return_value=True):
with patch("os.path.getsize", return_value=1024):
with patch("os.path.basename", return_value="file_123.jpg"):
with patch(
"os.path.splitext", return_value=("file_123", ".jpg")
):
with patch(
"helper_bot.utils.metrics.metrics"
) as mock_metrics:
result = await download_file(
mock_message, "file_id_123", "photo"
)
assert result == "files/photos/file_123.jpg"
mock_makedirs.assert_called()
mock_message.bot.get_file.assert_called_once_with(
"file_id_123"
)
mock_message.bot.download_file.assert_called_once()
@pytest.mark.asyncio
async def test_download_file_exception(self):
"""Тест обработки ошибки при скачивании"""
mock_message = Mock()
mock_message.bot = AsyncMock()
mock_message.bot.get_file.side_effect = Exception("Network error")
with patch("os.makedirs"):
with patch("helper_bot.utils.helper_func.logger") as mock_logger:
result = await download_file(mock_message, "file_id_123")
assert result is None
mock_logger.error.assert_called_once()
class TestPrepareMediaGroup:
"""Тесты для подготовки медиагрупп"""
@pytest.mark.asyncio
async def test_prepare_media_group_photos(self):
"""Тест подготовки медиагруппы с фотографиями"""
album = []
for i in range(3):
message = Mock()
message.photo = [Mock()]
message.photo[-1].file_id = f"photo_{i}"
album.append(message)
result = await prepare_media_group_from_middlewares(album, "Тестовая подпись")
assert len(result) == 3
assert result[0].media == "photo_0"
assert result[1].media == "photo_1"
assert result[2].media == "photo_2"
assert (
result[0].caption == "Тестовая подпись"
) # Первое фото должно иметь caption
@pytest.mark.asyncio
async def test_prepare_media_group_mixed_types(self):
"""Тест подготовки медиагруппы с разными типами медиа"""
album = []
# Фото
photo_message = Mock()
photo_message.photo = [Mock()]
photo_message.photo[-1].file_id = "photo_1"
album.append(photo_message)
# Видео
video_message = Mock()
video_message.photo = None
video_message.video = Mock()
video_message.video.file_id = "video_1"
album.append(video_message)
# Аудио
audio_message = Mock()
audio_message.photo = None
audio_message.video = None
audio_message.audio = Mock()
audio_message.audio.file_id = "audio_1"
album.append(audio_message)
result = await prepare_media_group_from_middlewares(album, "Смешанная группа")
assert len(result) == 3
assert result[0].media == "photo_1"
assert result[1].media == "video_1"
assert result[2].media == "audio_1"
assert (
result[0].caption == "Смешанная группа"
) # Первое медиа должно иметь caption
@pytest.mark.asyncio
async def test_prepare_media_group_empty_album(self):
"""Тест подготовки пустой медиагруппы"""
album = []
result = await prepare_media_group_from_middlewares(album, "Пустая группа")
assert result == []
@pytest.mark.asyncio
async def test_prepare_media_group_unsupported_type(self):
"""Тест подготовки медиагруппы с неподдерживаемым типом"""
album = []
message = Mock()
message.photo = None
message.video = None
message.audio = None
message.document = None # Добавляем document = None
album.append(message)
result = await prepare_media_group_from_middlewares(album, "Тест")
assert result == []
class TestMediaDatabaseOperations:
"""Тесты для операций с медиа в базе данных"""
@pytest.mark.asyncio
async def test_add_in_db_media_mediagroup(self):
"""Тест добавления медиагруппы в базу данных"""
sent_message = []
for i in range(2):
message = Mock()
message.message_id = i + 1
message.photo = [Mock()]
message.photo[-1].file_id = f"photo_{i}"
sent_message.append(message)
mock_db = AsyncMock()
with patch(
"helper_bot.utils.helper_func.download_file",
return_value=f"files/photo_{i}.jpg",
):
await add_in_db_media_mediagroup(sent_message, mock_db)
assert mock_db.add_post_content.call_count == 2
@pytest.mark.asyncio
async def test_add_in_db_media_photo(self):
"""Тест добавления фото в базу данных"""
mock_message = Mock()
mock_message.message_id = 123
mock_message.photo = [Mock()]
mock_message.photo[-1].file_id = "photo_123"
mock_db = AsyncMock()
with patch(
"helper_bot.utils.helper_func.download_file",
return_value="files/photo_123.jpg",
):
await add_in_db_media(mock_message, mock_db)
mock_db.add_post_content.assert_called_once_with(
123, 123, "files/photo_123.jpg", "photo"
)
@pytest.mark.asyncio
async def test_add_in_db_media_video(self):
"""Тест добавления видео в базу данных"""
mock_message = Mock()
mock_message.message_id = 123
mock_message.photo = None # У видео нет фото
mock_message.video = Mock()
mock_message.video.file_id = "video_123"
mock_db = AsyncMock()
with patch(
"helper_bot.utils.helper_func.download_file",
return_value="files/video_123.mp4",
):
await add_in_db_media(mock_message, mock_db)
mock_db.add_post_content.assert_called_once_with(
123, 123, "files/video_123.mp4", "video"
)
@pytest.mark.asyncio
async def test_add_in_db_media_voice(self):
"""Тест добавления голосового сообщения в базу данных"""
mock_message = Mock()
mock_message.message_id = 123
mock_message.photo = None # У голосового сообщения нет фото
mock_message.video = None # У голосового сообщения нет видео
mock_message.voice = Mock()
mock_message.voice.file_id = "voice_123"
mock_db = AsyncMock()
with patch(
"helper_bot.utils.helper_func.download_file",
return_value="files/voice_123.ogg",
):
await add_in_db_media(mock_message, mock_db)
mock_db.add_post_content.assert_called_once_with(
123, 123, "files/voice_123.ogg", "voice"
)
class TestSendMessageFunctions:
"""Тесты для функций отправки сообщений"""
@pytest.mark.asyncio
async def test_send_text_message_without_markup(self):
"""Тест отправки текстового сообщения без разметки"""
mock_message = Mock()
mock_message.bot = AsyncMock()
mock_message.bot.send_message = AsyncMock()
mock_sent_message = Mock()
mock_sent_message.message_id = 456
mock_message.bot.send_message.return_value = mock_sent_message
# Мокаем rate_limiter (он импортируется внутри функции)
with patch(
"helper_bot.utils.rate_limiter.send_with_rate_limit", new_callable=AsyncMock
) as mock_rate_limit:
mock_rate_limit.return_value = mock_sent_message
result = await send_text_message(123, mock_message, "Тестовое сообщение")
assert result == mock_sent_message
assert result.message_id == 456
@pytest.mark.asyncio
async def test_send_text_message_with_markup(self):
"""Тест отправки текстового сообщения с разметкой"""
mock_message = Mock()
mock_message.bot = AsyncMock()
mock_message.bot.send_message = AsyncMock()
mock_markup = Mock()
mock_sent_message = Mock()
mock_sent_message.message_id = 456
mock_message.bot.send_message.return_value = mock_sent_message
# Мокаем rate_limiter (он импортируется внутри функции)
with patch(
"helper_bot.utils.rate_limiter.send_with_rate_limit", new_callable=AsyncMock
) as mock_rate_limit:
mock_rate_limit.return_value = mock_sent_message
result = await send_text_message(
123, mock_message, "Тестовое сообщение", mock_markup
)
assert result == mock_sent_message
assert result.message_id == 456
@pytest.mark.asyncio
async def test_send_photo_message(self):
"""Тест отправки фото"""
mock_message = Mock()
mock_message.bot = AsyncMock()
mock_message.bot.send_photo = AsyncMock()
mock_sent_message = Mock()
mock_message.bot.send_photo.return_value = mock_sent_message
result = await send_photo_message(
123, mock_message, "photo.jpg", "Подпись к фото"
)
assert result == mock_sent_message
mock_message.bot.send_photo.assert_called_once_with(
chat_id=123, caption="Подпись к фото", photo="photo.jpg", parse_mode="HTML"
)
@pytest.mark.asyncio
async def test_send_video_message(self):
"""Тест отправки видео"""
mock_message = Mock()
mock_message.bot = AsyncMock()
mock_message.bot.send_video = AsyncMock()
mock_sent_message = Mock()
mock_message.bot.send_video.return_value = mock_sent_message
result = await send_video_message(
123, mock_message, "video.mp4", "Подпись к видео"
)
assert result == mock_sent_message
mock_message.bot.send_video.assert_called_once_with(
chat_id=123, caption="Подпись к видео", video="video.mp4", parse_mode="HTML"
)
class TestUtilityFunctions:
"""Тесты для утилитарных функций"""
@pytest.mark.asyncio
async def test_check_access(self):
"""Тест проверки доступа"""
mock_db = AsyncMock()
mock_db.is_admin.return_value = True
result = await check_access(123, mock_db)
assert result is True
mock_db.is_admin.return_value = False
result = await check_access(123, mock_db)
assert result is False
def test_add_days_to_date(self):
"""Тест добавления дней к дате"""
with patch("helper_bot.utils.helper_func.datetime") as mock_datetime:
from datetime import timedelta
mock_now = datetime(2024, 1, 1)
mock_datetime.now.return_value = mock_now
mock_datetime.timedelta = timedelta
result = add_days_to_date(5)
expected_timestamp = int((mock_now + timedelta(days=5)).timestamp())
assert result == expected_timestamp
@pytest.mark.asyncio
async def test_get_banned_users_list(self):
"""Тест получения списка заблокированных пользователей"""
mock_db = AsyncMock()
mock_db.get_banned_users_from_db_with_limits.return_value = [
# user_id, ban_reason, unban_date (timestamp), ban_date (timestamp)
(123, "Spam", 1704067200, 1703980800),
(456, "Violation", 1704153600, 1704067200),
]
mock_db.get_username.return_value = None
mock_db.get_full_name_by_id.return_value = "Test User"
result = await get_banned_users_list(0, mock_db)
assert "Список заблокированных пользователей:" in result
assert "Test User" in result
assert "Spam" in result
assert "Violation" in result
assert "<b>Дата бана:</b>" in result
@pytest.mark.asyncio
async def test_get_banned_users_list_with_string_timestamp(self):
"""Тест получения списка заблокированных пользователей со строковым timestamp"""
mock_db = AsyncMock()
mock_db.get_banned_users_from_db_with_limits.return_value = [
# user_id, ban_reason, unban_date (string timestamp), ban_date (string timestamp)
(123, "Spam", "1704067200", "1703980800"),
(456, "Violation", "1704153600", "1704067200"),
]
mock_db.get_username.return_value = None
mock_db.get_full_name_by_id.return_value = "Test User"
result = await get_banned_users_list(0, mock_db)
assert "Список заблокированных пользователей:" in result
assert "Test User" in result
assert "Spam" in result
assert "Violation" in result
assert "<b>Дата бана:</b>" in result
@pytest.mark.asyncio
async def test_get_banned_users_buttons(self):
"""Тест получения кнопок заблокированных пользователей"""
mock_db = AsyncMock()
mock_db.get_banned_users_from_db.return_value = [
(123, "Spam", 1704067200), # user_id, ban_reason, unban_date
(456, "Violation", 1704153600),
]
mock_db.get_username.return_value = None
mock_db.get_full_name_by_id.return_value = "Test User"
result = await get_banned_users_buttons(mock_db)
assert len(result) == 2
assert result[0] == ("Test User", 123)
assert result[1] == ("Test User", 456)
@pytest.mark.asyncio
async def test_delete_user_blacklist(self):
"""Тест удаления пользователя из черного списка"""
mock_db = AsyncMock()
mock_db.delete_user_blacklist.return_value = True
result = await delete_user_blacklist(123, mock_db)
assert result is True
mock_db.delete_user_blacklist.assert_called_once_with(user_id=123)
class TestUserManagement:
"""Тесты для управления пользователями"""
@pytest.mark.asyncio
async def test_update_user_info_new_user(self):
"""Тест обновления информации о новом пользователе"""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.from_user.full_name = "Test User"
mock_message.from_user.username = "testuser"
mock_message.from_user.is_bot = False
mock_message.from_user.language_code = "ru"
mock_message.answer = AsyncMock()
mock_message.bot.send_message = AsyncMock()
with patch("helper_bot.utils.helper_func.get_first_name", return_value="Test"):
with patch(
"helper_bot.utils.helper_func.get_random_emoji", return_value="😀"
):
with patch("helper_bot.utils.helper_func.BotDB") as mock_bot_db:
mock_bot_db.user_exists = AsyncMock(return_value=False)
mock_bot_db.add_user = AsyncMock()
mock_bot_db.update_user_date = AsyncMock()
await update_user_info("test", mock_message)
mock_bot_db.add_user.assert_called_once()
mock_bot_db.update_user_date.assert_called_once()
@pytest.mark.asyncio
async def test_check_user_emoji_existing(self):
"""Тест проверки эмодзи пользователя (существующий)"""
mock_message = Mock()
mock_message.from_user.id = 123
with patch("helper_bot.utils.helper_func.BotDB") as mock_bot_db:
mock_bot_db.get_user_emoji = AsyncMock(return_value="😀")
result = await check_user_emoji(mock_message)
assert result == "😀"
@pytest.mark.asyncio
async def test_check_user_emoji_new(self):
"""Тест проверки эмодзи пользователя (новый)"""
mock_message = Mock()
mock_message.from_user.id = 123
with patch("helper_bot.utils.helper_func.BotDB") as mock_bot_db:
mock_bot_db.get_user_emoji = AsyncMock(return_value=None)
mock_bot_db.update_user_emoji = AsyncMock()
with patch(
"helper_bot.utils.helper_func.get_random_emoji", return_value="😀"
):
result = await check_user_emoji(mock_message)
assert result == "😀"
mock_bot_db.update_user_emoji.assert_called_once_with(
user_id=123, emoji="😀"
)
@pytest.mark.asyncio
async def test_get_random_emoji_success(self):
"""Тест получения случайного эмодзи (успех)"""
with patch("helper_bot.utils.helper_func.BotDB") as mock_bot_db:
mock_bot_db.check_emoji_exists = AsyncMock(return_value=False)
with patch("helper_bot.utils.helper_func.random.choice", return_value="😀"):
result = await get_random_emoji()
assert result == "😀"
@pytest.mark.asyncio
async def test_get_random_emoji_fallback(self):
"""Тест получения случайного эмодзи (fallback)"""
with patch("helper_bot.utils.helper_func.BotDB") as mock_bot_db:
mock_bot_db.check_emoji_exists = AsyncMock(
return_value=True
) # Все эмодзи заняты
with patch("helper_bot.utils.helper_func.random.choice", return_value="😀"):
with patch("helper_bot.utils.helper_func.logger") as mock_logger:
result = await get_random_emoji()
assert result == "Эмоджи не определен"
mock_logger.error.assert_called_once()
if __name__ == "__main__":
pytest.main([__file__, "-v"])