mirror of
https://github.com/FerraSoft/bottohelp.git
synced 2026-08-07 14:15:02 +00:00
348 lines
14 KiB
Python
348 lines
14 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Комплексная система автоматического тестирования телеграм-бота.
|
||
Проверяет все команды, callback кнопки и обработчики сообщений.
|
||
"""
|
||
|
||
import asyncio
|
||
import sys
|
||
import os
|
||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
from unittest.mock import MagicMock, AsyncMock
|
||
from telegram import Update, User, Chat, Message, CallbackQuery
|
||
from telegram.ext import ContextTypes
|
||
from typing import Dict, List, Tuple
|
||
|
||
# Импортируем все компоненты бота
|
||
from core.application import Application
|
||
from handlers.user_handlers import UserHandlers
|
||
from handlers.game_handlers import GameHandlers
|
||
from handlers.admin_handlers import AdminHandlers
|
||
from services.user_service import UserService
|
||
from services.game_service import GameService
|
||
from database.repository import UserRepository, ScoreRepository
|
||
|
||
class ComprehensiveTestSuite:
|
||
"""Комплексная система тестирования бота"""
|
||
|
||
def __init__(self):
|
||
"""Инициализация тестера"""
|
||
self.results = {
|
||
'commands': [],
|
||
'callbacks': [],
|
||
'messages': [],
|
||
'errors': []
|
||
}
|
||
|
||
# Создаем мок-конфигурацию
|
||
self.mock_config = MagicMock()
|
||
self.mock_config.api_keys = MagicMock()
|
||
self.mock_config.api_keys.openweather = "test_key"
|
||
self.mock_config.api_keys.news = "test_key"
|
||
self.mock_config.api_keys.openai = "test_key"
|
||
self.mock_config.bot_config = MagicMock()
|
||
self.mock_config.bot_config.admin_ids = [1278359005]
|
||
self.mock_config.bot_config.enable_developer_notifications = True
|
||
self.mock_config.bot_config.developer_chat_id = 1278359005
|
||
|
||
# Создаем репозитории и сервисы
|
||
self.user_repo = UserRepository("telegram_bot.db")
|
||
self.score_repo = ScoreRepository("telegram_bot.db")
|
||
self.user_service = UserService(self.user_repo, self.score_repo)
|
||
self.game_service = GameService(self.user_repo, self.score_repo)
|
||
|
||
# Создаем обработчики
|
||
self.user_handlers = UserHandlers(self.mock_config, MagicMock(), self.user_service)
|
||
self.game_handlers = GameHandlers(self.mock_config, MagicMock(), self.game_service)
|
||
|
||
print("Комплексная система тестирования инициализирована")
|
||
|
||
def create_mock_update(self, text=None, callback_data=None, user_id=123456789,
|
||
username="test_user", first_name="Test", last_name="User"):
|
||
"""Создание мок-объекта Update"""
|
||
|
||
# Создаем мок-пользователя
|
||
user = MagicMock(spec=User)
|
||
user.id = user_id
|
||
user.username = username
|
||
user.first_name = first_name
|
||
user.last_name = last_name
|
||
|
||
# Создаем мок-сообщение
|
||
message = MagicMock(spec=Message)
|
||
message.text = text
|
||
message.message_id = 1
|
||
|
||
# Создаем мок-коллбек запрос
|
||
callback_query = MagicMock(spec=CallbackQuery)
|
||
callback_query.data = callback_data
|
||
callback_query.message = MagicMock()
|
||
callback_query.from_user = user
|
||
|
||
# Создаем мок-чат
|
||
chat = MagicMock(spec=Chat)
|
||
chat.id = -1001234567890
|
||
chat.type = "supergroup"
|
||
|
||
# Создаем мок-update
|
||
update = MagicMock(spec=Update)
|
||
update.effective_user = user
|
||
update.message = message if text else None
|
||
update.callback_query = callback_query if callback_data else None
|
||
update.effective_chat = chat
|
||
|
||
return update
|
||
|
||
def create_mock_context(self):
|
||
"""Создание мок-объекта ContextTypes"""
|
||
context = MagicMock(spec=ContextTypes)
|
||
context.args = []
|
||
context.bot = MagicMock()
|
||
context.user_data = {}
|
||
|
||
# Настраиваем асинхронные методы
|
||
context.bot.send_message = AsyncMock()
|
||
context.bot.edit_message_text = AsyncMock()
|
||
|
||
return context
|
||
|
||
async def test_single_command(self, command: str, description: str, handler, method_name: str) -> Dict:
|
||
"""Тестирование одной команды"""
|
||
result = {
|
||
'command': command,
|
||
'description': description,
|
||
'success': False,
|
||
'error': None,
|
||
'execution_time': 0
|
||
}
|
||
|
||
try:
|
||
import time
|
||
start_time = time.time()
|
||
|
||
# Создаем мок-объекты
|
||
update = self.create_mock_update(text=command)
|
||
context = self.create_mock_context()
|
||
|
||
# Получаем метод обработчика
|
||
method = getattr(handler, method_name)
|
||
|
||
# Выполняем команду
|
||
await method(update, context)
|
||
|
||
execution_time = time.time() - start_time
|
||
result['success'] = True
|
||
result['execution_time'] = execution_time
|
||
|
||
print(f"[SUCCESS] {command}: {execution_time:.3f}с")
|
||
|
||
except Exception as e:
|
||
result['error'] = str(e)
|
||
print(f"[ERROR] {command}: {e}")
|
||
self.results['errors'].append({
|
||
'command': command,
|
||
'error': str(e),
|
||
'traceback': str(e.__class__.__name__)
|
||
})
|
||
|
||
return result
|
||
|
||
async def test_callback_button(self, callback_data: str, description: str, handler, method_name: str) -> Dict:
|
||
"""Тестирование callback кнопки"""
|
||
result = {
|
||
'callback': callback_data,
|
||
'description': description,
|
||
'success': False,
|
||
'error': None,
|
||
'execution_time': 0
|
||
}
|
||
|
||
try:
|
||
import time
|
||
start_time = time.time()
|
||
|
||
# Создаем мок-объекты
|
||
update = self.create_mock_update(callback_data=callback_data)
|
||
context = self.create_mock_context()
|
||
|
||
# Получаем метод обработчика
|
||
method = getattr(handler, method_name)
|
||
|
||
# Выполняем обработчик
|
||
await method(update, context)
|
||
|
||
execution_time = time.time() - start_time
|
||
result['success'] = True
|
||
result['execution_time'] = execution_time
|
||
|
||
print(f"[SUCCESS] {callback_data}: {execution_time:.3f}с")
|
||
|
||
except Exception as e:
|
||
result['error'] = str(e)
|
||
print(f"[ERROR] {callback_data}: {e}")
|
||
self.results['errors'].append({
|
||
'callback': callback_data,
|
||
'error': str(e),
|
||
'traceback': str(e.__class__.__name__)
|
||
})
|
||
|
||
return result
|
||
|
||
async def run_command_tests(self):
|
||
"""Тестирование команд"""
|
||
print("\n" + "="*60)
|
||
print("ТЕСТИРОВАНИЕ КОМАНД")
|
||
print("="*60)
|
||
|
||
commands_to_test = [
|
||
("/start", "Запуск бота", self.user_handlers, "handle_start"),
|
||
("/help", "Помощь", self.user_handlers, "handle_help"),
|
||
("/rank", "Ранг пользователя", self.user_handlers, "handle_rank"),
|
||
("/leaderboard", "Таблица лидеров", self.user_handlers, "handle_leaderboard"),
|
||
("/info", "Информация о пользователе", self.user_handlers, "handle_info"),
|
||
("/donate", "Донаты", self.user_handlers, "handle_donate"),
|
||
("/play_game", "Меню игр", self.game_handlers, "handle_play_game"),
|
||
("/rock_paper_scissors", "Камень-ножницы-бумага", self.game_handlers, "handle_rock_paper_scissors"),
|
||
("/battleship", "Морской бой", self.game_handlers, "handle_battleship"),
|
||
]
|
||
|
||
for command, description, handler, method_name in commands_to_test:
|
||
result = await self.test_single_command(command, description, handler, method_name)
|
||
self.results['commands'].append(result)
|
||
|
||
async def run_callback_tests(self):
|
||
"""Тестирование callback кнопок"""
|
||
print("\n" + "="*60)
|
||
print("ТЕСТИРОВАНИЕ CALLBACK КНОПОК")
|
||
print("="*60)
|
||
|
||
callbacks_to_test = [
|
||
("menu_main", "Главное меню", self.user_handlers, "handle_main_menu"),
|
||
("menu_help", "Меню помощи", self.user_handlers, "handle_help_menu"),
|
||
("menu_rank", "Меню ранга", self.user_handlers, "handle_rank_menu"),
|
||
("game_rps_start", "Запуск RPS", self.game_handlers, "handle_rps_choice"),
|
||
("game_battleship_start", "Запуск морского боя", self.game_handlers, "handle_battleship_shot"),
|
||
("donate_100", "Донат 100", self.user_handlers, "handle_donation_callback"),
|
||
("donate_500", "Донат 500", self.user_handlers, "handle_donation_callback"),
|
||
("donate_1000", "Донат 1000", self.user_handlers, "handle_donation_callback"),
|
||
]
|
||
|
||
for callback_data, description, handler, method_name in callbacks_to_test:
|
||
result = await self.test_callback_button(callback_data, description, handler, method_name)
|
||
self.results['callbacks'].append(result)
|
||
|
||
async def test_database_operations(self):
|
||
"""Тестирование операций с базой данных"""
|
||
print("\n" + "="*60)
|
||
print("ТЕСТИРОВАНИЕ БАЗЫ ДАННЫХ")
|
||
print("="*60)
|
||
|
||
try:
|
||
# Тестируем создание пользователя
|
||
user_profile = await self.user_service.get_or_create_user(
|
||
999999999, "db_test_user", "DB", "Test"
|
||
)
|
||
|
||
if user_profile:
|
||
print(f"[SUCCESS] Пользователь создан: {user_profile.first_name}")
|
||
print(f" ID: {user_profile.user_id}")
|
||
print(f" Репутация: {user_profile.reputation}")
|
||
else:
|
||
print("[ERROR] Не удалось создать пользователя")
|
||
|
||
# Тестируем получение топ пользователей
|
||
top_users = await self.user_service.get_top_users(5)
|
||
print(f"[SUCCESS] Топ пользователей получен: {len(top_users)} записей")
|
||
|
||
# Тестируем обновление активности
|
||
activity_result = await self.user_service.update_user_activity(999999999, -1001234567890)
|
||
print(f"[SUCCESS] Активность обновлена: {activity_result}")
|
||
|
||
except Exception as e:
|
||
print(f"[ERROR] Ошибка базы данных: {e}")
|
||
|
||
def generate_report(self):
|
||
"""Генерация отчета о тестировании"""
|
||
print("\n" + "="*60)
|
||
print("ОТЧЕТ О ТЕСТИРОВАНИИ")
|
||
print("="*60)
|
||
|
||
total_commands = len(self.results['commands'])
|
||
successful_commands = len([r for r in self.results['commands'] if r['success']])
|
||
|
||
total_callbacks = len(self.results['callbacks'])
|
||
successful_callbacks = len([r for r in self.results['callbacks'] if r['success']])
|
||
|
||
total_errors = len(self.results['errors'])
|
||
|
||
print(f"Команды: {successful_commands}/{total_commands} успешных")
|
||
print(f"Callback кнопки: {successful_callbacks}/{total_callbacks} успешных")
|
||
print(f"Ошибок: {total_errors}")
|
||
|
||
# Подробный отчет по командам
|
||
print("\nДЕТАЛЬНЫЙ ОТЧЕТ ПО КОМАНДАМ:")
|
||
for result in self.results['commands']:
|
||
status = "SUCCESS" if result['success'] else "ERROR"
|
||
print(f" {result['command']:<20} | {status:<8} | {result['execution_time']:.3f}с")
|
||
|
||
# Подробный отчет по callback кнопкам
|
||
print("\nДЕТАЛЬНЫЙ ОТЧЕТ ПО CALLBACK КНОПКАМ:")
|
||
for result in self.results['callbacks']:
|
||
status = "SUCCESS" if result['success'] else "ERROR"
|
||
print(f" {result['callback']:<20} | {status:<8} | {result['execution_time']:.3f}с")
|
||
|
||
# Отчет об ошибках
|
||
if self.results['errors']:
|
||
print("\nОШИБКИ:")
|
||
for error in self.results['errors']:
|
||
if 'command' in error:
|
||
print(f" Команда {error['command']}: {error['error']}")
|
||
else:
|
||
print(f" Callback {error['callback']}: {error['error']}")
|
||
|
||
# Итоговая оценка
|
||
total_tests = total_commands + total_callbacks
|
||
successful_tests = successful_commands + successful_callbacks
|
||
success_rate = (successful_tests / total_tests * 100) if total_tests > 0 else 0
|
||
|
||
print(f"\nОБЩИЙ РЕЗУЛЬТАТ:")
|
||
print(f"Всего тестов: {total_tests}")
|
||
print(f"Успешных: {successful_tests}")
|
||
print(f"Процент успеха: {success_rate:.1f}%")
|
||
|
||
if success_rate >= 90:
|
||
print("ОЦЕНКА: ОТЛИЧНО - Бот готов к работе!")
|
||
elif success_rate >= 70:
|
||
print("ОЦЕНКА: ХОРОШО - Есть небольшие проблемы")
|
||
else:
|
||
print("ОЦЕНКА: ТРЕБУЕТ УЛУЧШЕНИЙ - Много ошибок")
|
||
|
||
async def run_all_tests(self):
|
||
"""Запуск всех тестов"""
|
||
print("НАЧАЛО КОМПЛЕКСНОГО ТЕСТИРОВАНИЯ ТЕЛЕГРАМ-БОТА")
|
||
print("=" * 70)
|
||
|
||
# Тестируем команды
|
||
await self.run_command_tests()
|
||
|
||
# Тестируем callback кнопки
|
||
await self.run_callback_tests()
|
||
|
||
# Тестируем базу данных
|
||
await self.test_database_operations()
|
||
|
||
# Генерируем отчет
|
||
self.generate_report()
|
||
|
||
print("\n" + "="*70)
|
||
print("ТЕСТИРОВАНИЕ ЗАВЕРШЕНО")
|
||
|
||
async def main():
|
||
"""Главная функция"""
|
||
# Создаем и запускаем тестовую систему
|
||
test_suite = ComprehensiveTestSuite()
|
||
await test_suite.run_all_tests()
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main()) |