cleaning root
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
This commit is contained in:
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests package
|
||||
135
tests/test_bot.py
Normal file
135
tests/test_bot.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Тестовый запуск бота - проверка импортов и конфигурации
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем путь к проекту
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
def test_imports():
|
||||
"""Тестирование всех импортов"""
|
||||
print("🔍 Проверка импортов...")
|
||||
|
||||
try:
|
||||
from config.config import config
|
||||
print("✅ config.config - OK")
|
||||
except ImportError as e:
|
||||
print(f"❌ config.config - {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
from src.database.database import DatabaseManager
|
||||
print("✅ src.database.database - OK")
|
||||
except ImportError as e:
|
||||
print(f"❌ src.database.database - {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
from src.services.csv_service import CSVQuizLoader, QuizGenerator
|
||||
print("✅ src.services.csv_service - OK")
|
||||
except ImportError as e:
|
||||
print(f"❌ src.services.csv_service - {e}")
|
||||
return False
|
||||
|
||||
# Проверим aiogram
|
||||
try:
|
||||
import aiogram
|
||||
print(f"✅ aiogram {aiogram.__version__} - OK")
|
||||
except ImportError as e:
|
||||
print(f"❌ aiogram - {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def test_config():
|
||||
"""Тестирование конфигурации"""
|
||||
print("\n⚙️ Проверка конфигурации...")
|
||||
|
||||
try:
|
||||
from config.config import config
|
||||
|
||||
print(f"🔑 BOT_TOKEN: {'✅ Настроен' if config.bot_token and config.bot_token != 'your_bot_token_here' else '❌ Не настроен'}")
|
||||
print(f"📁 DATABASE_PATH: {config.database_path}")
|
||||
print(f"📁 CSV_DATA_PATH: {config.csv_data_path}")
|
||||
print(f"🎲 QUESTIONS_PER_QUIZ: {config.questions_per_quiz}")
|
||||
print(f"🎯 GUEST_MODE_ENABLED: {config.guest_mode_enabled}")
|
||||
print(f"📚 TEST_MODE_ENABLED: {config.test_mode_enabled}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка конфигурации: {e}")
|
||||
return False
|
||||
|
||||
async def test_database():
|
||||
"""Тестирование базы данных"""
|
||||
print("\n🗄️ Проверка базы данных...")
|
||||
|
||||
try:
|
||||
from src.database.database import DatabaseManager
|
||||
from config.config import config
|
||||
|
||||
db = DatabaseManager(config.database_path)
|
||||
|
||||
# Проверим наличие файла БД
|
||||
if os.path.exists(config.database_path):
|
||||
print(f"✅ База данных найдена: {config.database_path}")
|
||||
else:
|
||||
print(f"❌ База данных не найдена: {config.database_path}")
|
||||
return False
|
||||
|
||||
# Проверим тесты
|
||||
tests = await db.get_tests_by_category()
|
||||
print(f"✅ Найдено тестов: {len(tests)}")
|
||||
|
||||
for test in tests[:3]: # Показываем первые 3
|
||||
questions = await db.get_random_questions(test['id'], 1)
|
||||
print(f" 📚 {test['name']}: {len(questions)} вопросов доступно")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка базы данных: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Основная функция тестирования"""
|
||||
print("🤖 Тестирование Quiz Bot")
|
||||
print("=" * 50)
|
||||
|
||||
# Тест импортов
|
||||
if not test_imports():
|
||||
print("\n❌ Ошибка импортов! Проверьте установку зависимостей.")
|
||||
return False
|
||||
|
||||
# Тест конфигурации
|
||||
if not test_config():
|
||||
print("\n❌ Ошибка конфигурации!")
|
||||
return False
|
||||
|
||||
# Тест базы данных (асинхронно)
|
||||
import asyncio
|
||||
if not asyncio.run(test_database()):
|
||||
print("\n❌ Ошибка базы данных!")
|
||||
return False
|
||||
|
||||
print("\n🎉 Все тесты прошли успешно!")
|
||||
|
||||
# Проверим готовность к запуску
|
||||
from config.config import config
|
||||
if config.bot_token and config.bot_token not in ['your_bot_token_here', 'test_token_for_demo_purposes']:
|
||||
print("\n✅ Бот готов к запуску!")
|
||||
print("🚀 Запустите: python src/bot.py")
|
||||
else:
|
||||
print("\n⚠️ Для запуска реального бота:")
|
||||
print("1. Получите токен у @BotFather")
|
||||
print("2. Замените BOT_TOKEN в .env файле")
|
||||
print("3. Запустите: python src/bot.py")
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
117
tests/test_bot_fix.py
Normal file
117
tests/test_bot_fix.py
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Тест для проверки работы бота после исправления ошибки Pydantic
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем путь к проекту
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
from aiogram.types import User, Chat, Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from src.bot import QuizBot
|
||||
from config.config import config
|
||||
|
||||
|
||||
async def create_mock_callback(user_id: int = 12345, data: str = "back_to_menu") -> CallbackQuery:
|
||||
"""Создаем мок callback query"""
|
||||
user = User(
|
||||
id=user_id,
|
||||
is_bot=False,
|
||||
first_name="Test",
|
||||
username="testuser"
|
||||
)
|
||||
|
||||
chat = Chat(id=user_id, type="private")
|
||||
|
||||
message = Message(
|
||||
message_id=1,
|
||||
date=1234567890,
|
||||
chat=chat,
|
||||
from_user=user,
|
||||
content_type="text",
|
||||
text="Test message"
|
||||
)
|
||||
|
||||
callback = CallbackQuery(
|
||||
id="test_callback",
|
||||
from_user=user,
|
||||
chat_instance="test",
|
||||
data=data,
|
||||
message=message
|
||||
)
|
||||
|
||||
return callback
|
||||
|
||||
|
||||
async def test_bot_handlers():
|
||||
"""Тестируем обработчики бота"""
|
||||
print("🧪 Тестирование обработчиков бота...")
|
||||
|
||||
# Создаем экземпляр бота
|
||||
bot = QuizBot()
|
||||
await bot.init_db()
|
||||
|
||||
try:
|
||||
# Тестируем stats_callback_handler
|
||||
print("📊 Тестируем stats_callback_handler...")
|
||||
callback = await create_mock_callback(data="stats")
|
||||
|
||||
# Этот вызов должен работать без ошибок
|
||||
await bot.stats_callback_handler(callback)
|
||||
print("✅ stats_callback_handler работает корректно")
|
||||
|
||||
# Тестируем back_to_menu
|
||||
print("🏠 Тестируем back_to_menu...")
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
|
||||
storage = MemoryStorage()
|
||||
context = FSMContext(
|
||||
storage=storage,
|
||||
key={'bot_id': bot.bot.id, 'chat_id': 12345, 'user_id': 12345}
|
||||
)
|
||||
|
||||
callback = await create_mock_callback(data="back_to_menu")
|
||||
|
||||
# Этот вызов должен работать без ошибок Pydantic
|
||||
await bot.back_to_menu(callback, context)
|
||||
print("✅ back_to_menu работает корректно")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка в тестах: {e}")
|
||||
return False
|
||||
|
||||
finally:
|
||||
await bot.db.close()
|
||||
|
||||
print("🎉 Все тесты пройдены успешно!")
|
||||
return True
|
||||
|
||||
|
||||
async def main():
|
||||
"""Главная функция"""
|
||||
print("=" * 50)
|
||||
print("🔧 Тест исправления ошибки Pydantic frozen instance")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
success = await test_bot_handlers()
|
||||
if success:
|
||||
print("\n✅ Исправление успешно! Бот готов к использованию.")
|
||||
return 0
|
||||
else:
|
||||
print("\n❌ Тесты не прошли. Требуется дополнительная отладка.")
|
||||
return 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n💥 Критическая ошибка: {e}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = asyncio.run(main())
|
||||
sys.exit(exit_code)
|
||||
218
tests/test_quiz.py
Normal file
218
tests/test_quiz.py
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Интерактивный тестер Quiz Bot
|
||||
Позволяет протестировать логику бота без Telegram
|
||||
"""
|
||||
import asyncio
|
||||
import random
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
project_root = Path(__file__).parent.parent
|
||||
sys.path.append(str(project_root))
|
||||
|
||||
from src.database.database import DatabaseManager
|
||||
from config.config import config
|
||||
|
||||
class LocalQuizTester:
|
||||
def __init__(self):
|
||||
self.db = DatabaseManager(config.database_path)
|
||||
self.user_id = 12345 # Тестовый ID пользователя
|
||||
|
||||
async def start_test(self):
|
||||
"""Интерактивный тест викторины"""
|
||||
print("🎮 Локальный тестер Quiz Bot")
|
||||
print("=" * 50)
|
||||
|
||||
# Регистрируем тестового пользователя
|
||||
await self.db.register_user(
|
||||
user_id=self.user_id,
|
||||
username="test_user",
|
||||
first_name="Test",
|
||||
last_name="User"
|
||||
)
|
||||
|
||||
while True:
|
||||
print("\n📋 Главное меню:")
|
||||
print("1. 🎯 Гостевой режим (быстрая викторина)")
|
||||
print("2. 📚 Режим тестирования (полный тест)")
|
||||
print("3. 📊 Моя статистика")
|
||||
print("4. ❌ Выход")
|
||||
|
||||
choice = input("\n👉 Ваш выбор (1-4): ").strip()
|
||||
|
||||
if choice == "1":
|
||||
await self.guest_mode()
|
||||
elif choice == "2":
|
||||
await self.test_mode()
|
||||
elif choice == "3":
|
||||
await self.show_stats()
|
||||
elif choice == "4":
|
||||
print("👋 До свидания!")
|
||||
break
|
||||
else:
|
||||
print("❌ Неверный выбор. Попробуйте снова.")
|
||||
|
||||
async def guest_mode(self):
|
||||
"""Гостевой режим - быстрая викторина"""
|
||||
print("\n🎯 Гостевой режим")
|
||||
await self.choose_test("guest")
|
||||
|
||||
async def test_mode(self):
|
||||
"""Режим полного тестирования"""
|
||||
print("\n📚 Режим тестирования")
|
||||
await self.choose_test("test")
|
||||
|
||||
async def choose_test(self, mode: str):
|
||||
"""Выбор теста"""
|
||||
tests = await self.db.get_tests_by_category("korean")
|
||||
|
||||
if not tests:
|
||||
print("❌ Тесты не найдены!")
|
||||
return
|
||||
|
||||
print(f"\n🇰🇷 Корейский язык - доступные уровни:")
|
||||
for i, test in enumerate(tests, 1):
|
||||
print(f"{i}. Уровень {test['level']} - {test['description']}")
|
||||
print("0. 🔙 Назад")
|
||||
|
||||
try:
|
||||
choice = int(input("\n👉 Выберите уровень: "))
|
||||
if choice == 0:
|
||||
return
|
||||
elif 1 <= choice <= len(tests):
|
||||
selected_test = tests[choice - 1]
|
||||
await self.start_quiz(selected_test, mode)
|
||||
else:
|
||||
print("❌ Неверный выбор!")
|
||||
except ValueError:
|
||||
print("❌ Введите число!")
|
||||
|
||||
async def start_quiz(self, test: dict, mode: str):
|
||||
"""Начало викторины"""
|
||||
test_id = test['id']
|
||||
|
||||
# Определяем количество вопросов
|
||||
if mode == "guest":
|
||||
questions_count = 5
|
||||
else:
|
||||
questions_count = 10
|
||||
|
||||
# Получаем случайные вопросы
|
||||
questions = await self.db.get_random_questions(test_id, questions_count)
|
||||
|
||||
if not questions:
|
||||
print("❌ Вопросы для этого теста не найдены!")
|
||||
return
|
||||
|
||||
# Начинаем сессию
|
||||
await self.db.start_session(
|
||||
user_id=self.user_id,
|
||||
test_id=test_id,
|
||||
questions=questions,
|
||||
mode=mode
|
||||
)
|
||||
|
||||
print(f"\n🎯 Начинаем тест: {test['name']}")
|
||||
print(f"📊 Количество вопросов: {len(questions)}")
|
||||
print(f"🎮 Режим: {'Гостевой' if mode == 'guest' else 'Тестирование'}")
|
||||
print("-" * 50)
|
||||
|
||||
correct_count = 0
|
||||
|
||||
# Проходим по вопросам
|
||||
for i, question in enumerate(questions, 1):
|
||||
print(f"\n❓ Вопрос {i} из {len(questions)}:")
|
||||
print(f"{question['question']}")
|
||||
print()
|
||||
print(f"1. {question['option1']}")
|
||||
print(f"2. {question['option2']}")
|
||||
print(f"3. {question['option3']}")
|
||||
print(f"4. {question['option4']}")
|
||||
|
||||
# Получаем ответ пользователя
|
||||
while True:
|
||||
try:
|
||||
user_answer = int(input("\n👉 Ваш ответ (1-4): "))
|
||||
if 1 <= user_answer <= 4:
|
||||
break
|
||||
else:
|
||||
print("❌ Введите число от 1 до 4!")
|
||||
except ValueError:
|
||||
print("❌ Введите число!")
|
||||
|
||||
# Проверяем ответ
|
||||
correct_answer = question['correct_answer']
|
||||
is_correct = user_answer == correct_answer
|
||||
|
||||
if is_correct:
|
||||
print("✅ Правильно!")
|
||||
correct_count += 1
|
||||
else:
|
||||
print(f"❌ Неправильно. Правильный ответ: {correct_answer}")
|
||||
|
||||
# Обновляем прогресс
|
||||
await self.db.update_session_progress(self.user_id, i, correct_count)
|
||||
|
||||
# Пауза перед следующим вопросом
|
||||
if i < len(questions):
|
||||
input("\n⏵️ Нажмите Enter для следующего вопроса...")
|
||||
|
||||
# Подсчитываем результат
|
||||
score = (correct_count / len(questions)) * 100
|
||||
await self.db.finish_session(self.user_id, score)
|
||||
|
||||
# Показываем результат
|
||||
print("\n" + "=" * 50)
|
||||
print("🎉 Тест завершен!")
|
||||
print(f"📊 Результат: {correct_count}/{len(questions)}")
|
||||
print(f"📈 Точность: {score:.1f}%")
|
||||
print(f"🏆 Оценка: {self.get_grade(score)}")
|
||||
print("=" * 50)
|
||||
|
||||
input("\n⏵️ Нажмите Enter для возврата в меню...")
|
||||
|
||||
async def show_stats(self):
|
||||
"""Показать статистику пользователя"""
|
||||
stats = await self.db.get_user_stats(self.user_id)
|
||||
|
||||
print("\n📊 Ваша статистика:")
|
||||
print("-" * 30)
|
||||
|
||||
if not stats or stats['total_questions'] == 0:
|
||||
print("📈 У вас пока нет статистики.")
|
||||
print("🎯 Пройдите первый тест!")
|
||||
else:
|
||||
accuracy = (stats['correct_answers'] / stats['total_questions']) * 100 if stats['total_questions'] > 0 else 0
|
||||
|
||||
print(f"❓ Всего вопросов: {stats['total_questions']}")
|
||||
print(f"✅ Правильных ответов: {stats['correct_answers']}")
|
||||
print(f"📈 Точность: {accuracy:.1f}%")
|
||||
print(f"🎯 Завершенных сессий: {stats['sessions_completed'] or 0}")
|
||||
|
||||
if stats['best_score']:
|
||||
print(f"🏆 Лучший результат: {stats['best_score']:.1f}%")
|
||||
if stats['average_score']:
|
||||
print(f"📊 Средний балл: {stats['average_score']:.1f}%")
|
||||
|
||||
input("\n⏵️ Нажмите Enter для возврата в меню...")
|
||||
|
||||
def get_grade(self, score: float) -> str:
|
||||
"""Получение оценки по проценту"""
|
||||
if score >= 90:
|
||||
return "Отлично! 🌟"
|
||||
elif score >= 70:
|
||||
return "Хорошо! 👍"
|
||||
elif score >= 50:
|
||||
return "Удовлетворительно 📚"
|
||||
else:
|
||||
return "Нужно подтянуть знания 📖"
|
||||
|
||||
|
||||
async def main():
|
||||
tester = LocalQuizTester()
|
||||
await tester.start_test()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 Запуск интерактивного тестера...")
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user