cleaning root
Some checks reported errors
continuous-integration/drone/push Build encountered an error

This commit is contained in:
2025-09-11 08:18:31 +09:00
parent fcf27c1639
commit b0346e4bd7
26 changed files with 352 additions and 159 deletions

1
tests/__init__.py Normal file
View File

@@ -0,0 +1 @@
# Tests package

135
tests/test_bot.py Normal file
View 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
View 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
View 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())