Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Добавлены тесты #15

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions app/bot/handlers.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import logging
from aiogram import Router
from aiogram import Router, Bot
from aiogram.filters import CommandStart, Command
from aiogram.types import Message
from sqlalchemy.ext.asyncio import AsyncSession
from admin.keyboards.keyboards import get_inline_keyboard
from const import MAIN_MENU_BUTTONS
from bot.bot_const import (
from app.admin.keyboards.keyboards import get_inline_keyboard
from app.const import MAIN_MENU_BUTTONS
from app.bot.bot_const import (
ADMIN_NEGATIVE_ANSWER, ADMIN_POSITIVE_ANSWER, START_MESSAGE
)
from models.models import RoleEnum
from crud.users import (
from app.models.models import RoleEnum
from app.crud.users import (
create_user_id, get_role_by_tg_id, is_user_in_db
)
from bot.keyborads import main_keyboard
from bot.exceptions import message_exception_handler
from helpers import get_user_id
from app.bot.keyborads import main_keyboard
from app.bot.exceptions import message_exception_handler
from app.helpers import get_user_id

router = Router()

Expand All @@ -25,19 +25,23 @@
log_error_text='Ошибка при обработке команды /admin.'
)
@router.message(Command('admin'))
async def cmd_admin(message: Message, session: AsyncSession) -> None:
async def cmd_admin(message: Message, session: AsyncSession, bot: Bot) -> None:
"""Вход в админку."""

user_id = get_user_id(message)
role = await get_role_by_tg_id(user_id, session)

if role in (RoleEnum.ADMIN, RoleEnum.MANAGER):
await message.answer(
ADMIN_POSITIVE_ANSWER,
await bot.send_message(
chat_id=message.chat.id,
text=ADMIN_POSITIVE_ANSWER,
reply_markup=await get_inline_keyboard(MAIN_MENU_BUTTONS)
)
else:
await message.answer(ADMIN_NEGATIVE_ANSWER)
await bot.send_message(
chat_id=message.chat.id,
text=ADMIN_NEGATIVE_ANSWER
)

logger.info(
f'Пользователь {user_id} вызвал команду /admin.'
Expand All @@ -48,16 +52,17 @@ async def cmd_admin(message: Message, session: AsyncSession) -> None:
log_error_text='Ошибка при обработке команды /start.'
)
@router.message(CommandStart())
async def cmd_start(message: Message, session: AsyncSession) -> None:
async def cmd_start(message: Message, session: AsyncSession, bot: Bot) -> None:
"""Выводит приветствие пользователя."""

user_id = get_user_id(message)

if not await is_user_in_db(user_id, session):
await create_user_id(user_id, session)

await message.answer(
START_MESSAGE,
await bot.send_message(
chat_id=message.chat.id,
text=START_MESSAGE,
reply_markup=main_keyboard
)

Expand Down
6 changes: 3 additions & 3 deletions app/bot/keyborads.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
InlineKeyboardMarkup, InlineKeyboardButton
)
from aiogram.utils.keyboard import InlineKeyboardBuilder
from crud.questions import get_question_by_title
from crud.projects import get_all_prtfolio_projects, get_categories_by_name
from models.models import CheckCompanyPortfolio, ProductCategory
from app.crud.questions import get_question_by_title
from app.crud.projects import get_all_prtfolio_projects, get_categories_by_name
from app.models.models import CheckCompanyPortfolio, ProductCategory
from sqlalchemy.ext.asyncio import AsyncSession

back_to_main_menu = InlineKeyboardButton(
Expand Down
21 changes: 18 additions & 3 deletions app/const.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import os

from dotenv import load_dotenv

# Загружаем переменные окружения из файла .env
load_dotenv()

TELEGRAM_CHAT_IDS = os.getenv("TELEGRAM_CHAT_IDS").split(", ")
admin_list = [int(admin_id) for admin_id in TELEGRAM_CHAT_IDS]
# Получаем TELEGRAM_CHAT_IDS из переменных окружения
chat_ids = os.getenv("TELEGRAM_CHAT_IDS")
if chat_ids:
try:
TELEGRAM_CHAT_IDS = [int(admin_id.strip()) for admin_id in chat_ids.split(
",") if admin_id.strip().isdigit()]
except ValueError as e:
print(f"Ошибка при обработке TELEGRAM_CHAT_IDS: {e}")
TELEGRAM_CHAT_IDS = []
else:
TELEGRAM_CHAT_IDS = []

# Если список пуст, предупреждаем пользователя (только для тестов)
if not TELEGRAM_CHAT_IDS:
print("Предупреждение: TELEGRAM_CHAT_IDS не были заданы или заданы некорректно.")

admin_list = TELEGRAM_CHAT_IDS


def get_buttons(menu: dict[str, str]) -> list[str]:
Expand Down
5 changes: 3 additions & 2 deletions app/core/settings.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
from pydantic_settings import BaseSettings
from pydantic import ConfigDict


class Settings(BaseSettings):
database_url: str
bot_token: str
telegram_token: str
telegram_chat_ids: str
email: str
email_password: str
postgres_user: str
postgres_password: str
postgres_db: str

class Config:
env_file = '.env'
model_config = ConfigDict(env_file='.env')


settings = Settings()
2 changes: 1 addition & 1 deletion app/crud/projects.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sqlalchemy.ext.asyncio import AsyncSession
from models.models import (
from app.models.models import (
CheckCompanyPortfolio, ProductCategory,
CategoryType
)
Expand Down
2 changes: 1 addition & 1 deletion app/crud/questions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sqlalchemy.ext.asyncio import AsyncSession
from models.models import Info
from app.models.models import Info

from sqlalchemy import select

Expand Down
2 changes: 1 addition & 1 deletion app/crud/users.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sqlalchemy.ext.asyncio import AsyncSession
from models.models import User
from app.models.models import User
from sqlalchemy import select


Expand Down
12 changes: 11 additions & 1 deletion app/helpers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
from aiogram.types import Message
import re


def get_user_id(message: Message) -> int:
"""Получает ID пользователя из сообщения."""

return message.from_user.id


def is_valid_name(name: str) -> bool:
"""Проверяет, что имя содержит только буквы."""
return bool(re.match(r'^[a-zA-Zа-яА-ЯёЁ]+$', name))


def is_valid_phone_number(phone_number: str) -> bool:
"""Проверяет, что номер телефона соответствует шаблону +7XXXXXXXXXX или 8XXXXXXXXXX."""
return bool(re.match(r'^(\+7|8)\d{10}$', phone_number))
2 changes: 1 addition & 1 deletion app/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from enum import Enum

from core.db import Base
from app.core.db import Base


class RoleEnum(str, Enum):
Expand Down
105 changes: 104 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ sqlalchemy = "^2.0.35"
pydantic-settings = "^2.5.2"
asyncpg = "^0.29.0"
aiosmtplib = "^3.0.2"
pytest = "^8.0.0"
pytest-asyncio = "^0.24.0"
pytest-mock = "^3.6.1"

[tool.poetry.group.dev.dependencies]
aiosqlite = "^0.20.0"
pytest-mock = "^3.14.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"
Empty file added tests/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import pytest
from aiogram.types import Message


@pytest.fixture
def fake_message():
return Message(chat={'id': 123}, text='/start')
41 changes: 41 additions & 0 deletions tests/test_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import datetime
import pytest
from unittest.mock import AsyncMock
from aiogram import Bot
from aiogram.types import Chat, Message, User
from sqlalchemy.ext.asyncio import AsyncSession
from app.bot.handlers import cmd_start
from app.bot.keyborads import main_keyboard
from app.bot.bot_const import START_MESSAGE


@pytest.mark.asyncio
async def test_cmd_start():
mock_session = AsyncMock(spec=AsyncSession)
mock_session.execute.return_value = AsyncMock().return_value

# Создаем мок-объект для бота
mock_bot = AsyncMock(spec=Bot)

chat = Chat(id=123, type='private')

# Создаем фейковый объект User с ID и именем пользователя
user = User(id=456, is_bot=False, first_name="TestUser")

# Создаем фейковое сообщение с обязательными полями
message = Message(
message_id=1, # уникальный идентификатор сообщения
date=datetime.datetime.now(), # время отправки сообщения
chat=chat, # чат, в который было отправлено сообщение
from_user=user, # пользователь, отправивший сообщение
text='/start' # текст сообщения
)

await cmd_start(message, mock_session, mock_bot)

# Проверяем, что бот вызвал метод send_message
mock_bot.send_message.assert_called_with(
chat_id=123,
text=START_MESSAGE,
reply_markup=main_keyboard
)
Loading