mirror of
https://github.com/FerraSoft/bottohelp.git
synced 2026-08-06 21:55:03 +00:00
Подготовка к релизу
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
Конфигурация pytest для телеграм-бота.
|
||||
Содержит фикстуры и вспомогательные функции для тестирования.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import pytest
|
||||
import asyncio
|
||||
from unittest.mock import Mock, AsyncMock
|
||||
from datetime import datetime
|
||||
from telegram import Update, User, Message, Chat, CallbackQuery
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
# Добавляем корневую директорию в путь
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from core.config import Config
|
||||
from core.exceptions import BotException, ValidationError, DatabaseError
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_config():
|
||||
"""Фикстура с тестовой конфигурацией"""
|
||||
# Создаем конфигурацию с пустыми списками админов для чистых тестов
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||
f.write("""
|
||||
BOT_TOKEN = "123456789:test_token_for_testing"
|
||||
ADMIN_IDS = []
|
||||
SUPER_ADMIN_IDS = []
|
||||
MODERATOR_IDS = []
|
||||
OPENWEATHER_API_KEY = "test_weather_key"
|
||||
NEWS_API_KEY = "test_news_key"
|
||||
OPENAI_API_KEY = "test_openai_key"
|
||||
""")
|
||||
temp_config_path = f.name
|
||||
|
||||
try:
|
||||
config = Config(temp_config_path)
|
||||
yield config
|
||||
finally:
|
||||
if os.path.exists(temp_config_path):
|
||||
os.unlink(temp_config_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_user():
|
||||
"""Фикстура с мок-объектом пользователя"""
|
||||
user = Mock(spec=User)
|
||||
user.id = 123456789
|
||||
user.username = "test_user"
|
||||
user.first_name = "Test"
|
||||
user.last_name = "User"
|
||||
user.is_bot = False
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_chat():
|
||||
"""Фикстура с мок-объектом чата"""
|
||||
chat = Mock(spec=Chat)
|
||||
chat.id = -1001234567890
|
||||
chat.type = "group"
|
||||
chat.title = "Test Chat"
|
||||
return chat
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_message(mock_user, mock_chat):
|
||||
"""Фикстура с мок-объектом сообщения"""
|
||||
message = Mock(spec=Message)
|
||||
message.message_id = 12345
|
||||
message.text = "/test command"
|
||||
message.from_user = mock_user
|
||||
message.chat = mock_chat
|
||||
message.date = datetime.now()
|
||||
message.reply_text = AsyncMock()
|
||||
message.set_reaction = AsyncMock()
|
||||
return message
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_update(mock_message):
|
||||
"""Фикстура с мок-объектом обновления"""
|
||||
update = Mock(spec=Update)
|
||||
update.effective_user = mock_message.from_user
|
||||
update.effective_chat = mock_message.chat
|
||||
update.message = mock_message
|
||||
update.callback_query = None
|
||||
return update
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_context():
|
||||
"""Фикстура с мок-объектом контекста"""
|
||||
context = Mock(spec=ContextTypes.DEFAULT_TYPE)
|
||||
context.args = []
|
||||
context.user_data = {}
|
||||
context.chat_data = {}
|
||||
context.bot = Mock()
|
||||
context.bot.send_message = AsyncMock()
|
||||
context.application = Mock()
|
||||
context.application._date_time = datetime.now()
|
||||
return context
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_callback_query(mock_user, mock_chat, mock_message):
|
||||
"""Фикстура с мок-объектом callback query"""
|
||||
callback_query = Mock(spec=CallbackQuery)
|
||||
callback_query.id = "test_callback_123"
|
||||
callback_query.data = "test_data"
|
||||
callback_query.from_user = mock_user
|
||||
callback_query.message = mock_message
|
||||
callback_query.answer = AsyncMock()
|
||||
callback_query.edit_message_text = AsyncMock()
|
||||
return callback_query
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_user_data():
|
||||
"""Фикстура с тестовыми данными пользователя"""
|
||||
return {
|
||||
'id': 123456789,
|
||||
'telegram_id': 123456789,
|
||||
'username': 'test_user',
|
||||
'first_name': 'Test',
|
||||
'last_name': 'User',
|
||||
'reputation': 150,
|
||||
'rank': 'Активист',
|
||||
'message_count': 45,
|
||||
'joined_date': datetime.now(),
|
||||
'last_activity': datetime.now()
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_error_data():
|
||||
"""Фикстура с тестовыми данными ошибки"""
|
||||
return {
|
||||
'id': 1,
|
||||
'admin_id': 123456789,
|
||||
'error_type': 'bug',
|
||||
'title': 'Тестовая ошибка',
|
||||
'description': 'Описание тестовой ошибки для тестирования',
|
||||
'status': 'new',
|
||||
'priority': 'medium',
|
||||
'created_at': datetime.now(),
|
||||
'updated_at': datetime.now()
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_db_path():
|
||||
"""Фикстура с временным путем к базе данных"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
||||
db_path = f.name
|
||||
|
||||
yield db_path
|
||||
|
||||
# Очистка после теста
|
||||
if os.path.exists(db_path):
|
||||
os.unlink(db_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event_loop():
|
||||
"""Фикстура для event loop (для асинхронных тестов)"""
|
||||
loop = asyncio.new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
# Вспомогательные функции для тестов
|
||||
|
||||
def create_test_config(bot_token: str = "123456789:test_token", admin_ids: list = None) -> Config:
|
||||
"""Создание тестовой конфигурации"""
|
||||
if admin_ids is None:
|
||||
admin_ids = [] # По умолчанию пустой список админов для тестов
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
||||
f.write(f"""
|
||||
BOT_TOKEN = "{bot_token}"
|
||||
ADMIN_IDS = {admin_ids}
|
||||
SUPER_ADMIN_IDS = []
|
||||
MODERATOR_IDS = []
|
||||
OPENWEATHER_API_KEY = "test_weather_key"
|
||||
NEWS_API_KEY = "test_news_key"
|
||||
OPENAI_API_KEY = "test_openai_key"
|
||||
""")
|
||||
config_path = f.name
|
||||
|
||||
try:
|
||||
return Config(config_path)
|
||||
finally:
|
||||
if os.path.exists(config_path):
|
||||
os.unlink(config_path)
|
||||
|
||||
|
||||
def assert_exception_raised(func, exception_type, *args, **kwargs):
|
||||
"""Утилита для проверки исключений в тестах"""
|
||||
with pytest.raises(exception_type):
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
asyncio.run(func(*args, **kwargs))
|
||||
else:
|
||||
func(*args, **kwargs)
|
||||
|
||||
|
||||
async def async_assert_exception_raised(func, exception_type, *args, **kwargs):
|
||||
"""Асинхронная утилита для проверки исключений"""
|
||||
with pytest.raises(exception_type):
|
||||
await func(*args, **kwargs)
|
||||
|
||||
|
||||
def create_mock_user(user_id: int = 123456789, username: str = "test_user",
|
||||
first_name: str = "Test", last_name: str = "User"):
|
||||
"""Создание мок-объекта пользователя"""
|
||||
user = Mock(spec=User)
|
||||
user.id = user_id
|
||||
user.username = username
|
||||
user.first_name = first_name
|
||||
user.last_name = last_name
|
||||
user.is_bot = False
|
||||
return user
|
||||
|
||||
|
||||
def create_mock_chat(chat_id: int = -1001234567890, chat_type: str = "group"):
|
||||
"""Создание мок-объекта чата"""
|
||||
chat = Mock(spec=Chat)
|
||||
chat.id = chat_id
|
||||
chat.type = chat_type
|
||||
return chat
|
||||
|
||||
|
||||
def create_mock_update(user: User = None, chat: Chat = None, text: str = "/test"):
|
||||
"""Создание мок-объекта обновления"""
|
||||
if user is None:
|
||||
user = create_mock_user()
|
||||
if chat is None:
|
||||
chat = create_mock_chat()
|
||||
|
||||
message = Mock(spec=Message)
|
||||
message.text = text
|
||||
message.from_user = user
|
||||
message.chat = chat
|
||||
|
||||
update = Mock(spec=Update)
|
||||
update.effective_user = user
|
||||
update.effective_chat = chat
|
||||
update.message = message
|
||||
|
||||
return update
|
||||
Reference in New Issue
Block a user