Этот проект представляет собой Telegram-бота на языке Python (библиотека telebot), интегрированного с базой данных SQLite. Бот предназначен для отслеживания циклов сна: пользователи могут фиксировать время начала и окончания сна, оценивать его качество и добавлять заметки.
В проекте реализована надежная система CRUD-операций, продвинутое логирование с разделением потоков данных и полное покрытие интеграционными тестами.
- Регистрация: Автоматическое создание профиля пользователя при первом взаимодействии.
- Трекинг сна: Запись времени отхода ко сну и пробуждения.
- Оценка качества: Возможность поставить оценку каждой сессии сна.
- Заметки: Добавление и редактирование комментариев к записям о сне.
- Логирование: Цветной вывод в консоль и хранение логов в отдельных файлах для удобного дебаггинга.
SleepBotProject/
├── sleep_bot.py # Основной файл приложения и хендлеры бота
├── database_manager.py # Логика взаимодействия с БД (CRUD)
├── sleep_tracker.db # База данных SQLite
├── test_database_manager.py # Интеграционные тесты для БД
├── test_sleep_bot.py # Интеграционные тесты для функций бота
├── my_logger_config.py # Модуль с настройками логирования и инициализацией логгеров
├── my_logging_config.yaml # YAML-файл конфигурации для логирования
├── my_color_formatter.py # Кастомный форматтер для цветного вывода логов в консоль
└── logs/ # Директория с файлами логов
├── app.log # Информационные логи приложения
└── error.log # Логи ошибок и исключений
Приложение работает с базой данных SQLite sleep_tracker.db, содержащей три таблицы users, sleep_records, notes.
Таблица users имеет следующую структуру:
| Колонка | Тип данных | Описание
|:----------|:-----------|:------------------------------------
| `id` | INTEGER | Уникальный идентификатор пользователя (PRIMARY KEY, AUTOINCREMENT)
| `name` | TEXT | Имя пользователя (NOT NULL)
Таблица sleep_records имеет следующую структуру:
| Колонка | Тип данных | Описание
|:---------------|:-----------|:------------------------------------
| `id` | INTEGER | Уникальный идентификатор сессии сна(PRIMARY KEY, AUTOINCREMENT)
| `user_id` | INTEGER | ID пользователя (FOREIGN KEY, NOT NULL)
| `sleep_time` | DATETIME | Время начала сна
| `wake_time` | DATETIME | Время пробуждения
| `sleep_quality`| INTEGER | Оценка качества сна
Таблица notes имеет следующую структуру:
| Колонка | Тип данных | Описание
|:-----------------|:-----------|:------------------------------------
| `id` | INTEGER | Уникальный идентификатор сессии сна(PRIMARY KEY, AUTOINCREMENT)
| `notes_text` | TEXT | Текст заметки(комментария) к оценке качества
| `sleep_record_id`| DATETIME | ID сессии сна (FOREIGN KEY, NOT NULL UNIQUE)
Python 3.10+telebot(для создания Telegram-бота)sqlite3(встроен в стандартную библиотеку Python)pytest(для запуска тестов)PyYAML(для загрузки конфигурации логирования)Colorama- (для цветного вывода логов в консоль)
- Клонировать репозиторий:
git clone <URL_РЕПОЗИТОРИЯ>
cd <ИМЯ_ПАПКИ_ПРОЕКТА>
- Установить необходимые библиотеки (инструкцию см. ниже).
- Запустить приложение:
python sleep_bot.py
- В командной строке или окне терминала ввести команду
- Нажать кнопку Enter
pip install PyYAML- Для установки библиотеки PyYAMLpip install colorama- Для установки библиотеки Coloramapip install pytest- Для установки библиотеки PyTestpip install pyTelegramBotAPI- Для установки библиотеки telebot
После запуска бота доступны следующие шаги:
- Отправьте команду
/startдля регистрации. - Используйте кнопку 'Сладких снов 😴' или команду
/sleep, чтобы зафиксировать время начала сна. - Нажмите кнопку 'Я проснулся ☀' или команду
/wake, чтобы завершить сессию сна. - Нажмите кнопку 'Качество сна 💫' и выберите оценку качества (1-5) на появившейся клавиатуре.
- Используйте кнопку 'Заметки 📝' или команду
/notes, чтобы добавить комментарий к оценке сна (например, 'Спалось нормально').
Приложение реализует комплексную систему логирования, которая:
- Записывает все события приложения(действия пользователя, изменения в БД) и ошибки.
- Использует различные уровни логирования (INFO, WARNING, ERROR, DEBUG, CRITICAL).
- Обеспечивает цветной вывод в консоль для лучшей читаемости.
- Хранит логи в отдельных файлах(app.log для общей информации, error.log для ошибок) в директории
logs/.
- app.log: Содержит общую информацию о работе приложения, включая действия пользователя, успешное выполнение операций с базой данных и информационные сообщения.
- error.log: Записывает все сообщения уровня
ERRORи выше, включая ошибки выполнения запросов к БД, исключения и критические сбои.
Настройка системы логирования осуществляется через следующие файлы:
- my_logger_config.py: Настраивает конфигурацию логирования
- my_logging_config.yaml: Конфигурация для различных логгеров
- my_color_formatter.py: Кастомный форматтер для цветного вывода в консоль
Проект придерживается интеграционного тестирования. Вместо простых unit-тестов проверяются целые цепочки взаимодействия.
Особенности тестов:
- Изоляция: Каждому тесту создается временная файловая база данных(через фикстуру pytest), что гарантирует чистоту данных.
- Мокирование (unittest.mock):
- Telegram API: Имитация ответов от серверов Telegram, что позволяет запускать тесты без реального токена и интернет-соединения.
- Тестирование отказоустойчивости: Использование
patchдля имитации сбоев в работеSQLite. Это позволяет проверить корректность обработки исключений (блоки try...except) и надежность записи логов ошибок в файлerror.log.
Тесты можно запустить из командной строки:
pytest- Краткий вариант результатов тестированияpytest -v- Более детальный вывод результатов тестирования
Также файл с тестированием можно запустить как и обычный код, через кнопку run.
import pytest
import sqlite3
from database_manager import DatabaseManager
def test_add_user_successfully(db_manager: DatabaseManager, caplog: pytest.LogCaptureFixture):
"""
Тестирует, что метод add_user успешно добавляет пользователя с указанными ID и именем.
Ожидается, что add_user запишет сообщение об успешном выполнении метода в лог.
:param db_manager: DatabaseManager: Менеджер базы данных, предоставляемый фикстурой.
:param caplog: pytest.LogCaptureFixture: Фикстура pytest для перехвата сообщений логгера.
"""
user_id = 1
user_name = 'TestUser'
db_manager.add_user(user_id, user_name)
with sqlite3.connect(db_manager.db_name) as conn:
cursor = conn.cursor()
cursor.execute("SELECT id, name FROM users WHERE id = ?", (user_id,))
user = cursor.fetchone()
conn.close()
assert user == (user_id, user_name)
expected_log_message = f'Пользователь {user_name} ({user_id}) добавлен или уже существует в БД {db_manager.db_name}.'
assert expected_log_message in caplog.textimport pytest
from unittest.mock import MagicMock, patch
with patch('telebot.TeleBot') as mocked_bot_class:
mock_bot_instance = MagicMock()
mock_bot_instance.message_handler.return_value = lambda func: func
mock_bot_instance.callback_query_handler.return_value = lambda func: func
mocked_bot_class.return_value = mock_bot_instance
import sleep_bot
from pytest_mock import MockFixture
@pytest.mark.parametrize('command_to_test, handler_name', [
('/sleep', 'handle_sleep'),
('/wake', 'handle_wake'),
('/quality', 'handle_quality'),
('/notes', 'handle_notes'),
('/recom', 'handle_recom'),
('/statis', 'handle_statistics')
])
def test_handle_callback_routing(test_db, mocker: MockFixture, command_to_test: str, handler_name: str) -> None:
"""
Тестирует роутинг: что нажатие на inline кнопку вызывает правильную функцию-обработчик.
:param test_db: Фикстура тестовой базы данных.
:param mocker: MockFixture: Объект для имитации вызова функции (mocking).
:param command_to_test: Ключ к тестируемой команде.
:param handler_name: Ключ к имени хендлера для тестируемой команды.
"""
call = MagicMock()
call.id = 'test_id'
call.data = command_to_test
call.message.chat.id = 123
mocked_handler = mocker.patch(f'sleep_bot.{handler_name}')
sleep_bot.bot.answer_callback_query.reset_mock()
sleep_bot.handle_callback(call)
mocked_handler.assert_called_once_with(call.message)
sleep_bot.bot.answer_callback_query.assert_called_once_with(call.id)