AI-Trend-Scout/tests/bot/test_handlers.py
Artur Mukhamadiev 9c8e4c7345 [tg] stats/search features
Processed data is not written back to user
2026-03-13 12:50:49 +03:00

176 lines
6.0 KiB
Python

import uuid
import pytest
from unittest.mock import AsyncMock, MagicMock
from aiogram.types import Message, InlineKeyboardMarkup, CallbackQuery
from aiogram.filters import CommandObject
from datetime import datetime
from src.bot.handlers import get_router, AccessMiddleware
from src.processor.dto import EnrichedNewsItemDTO
@pytest.fixture
def mock_item():
return EnrichedNewsItemDTO(
title="Breakthrough in Quantum Computing",
url="https://example.com/quantum-breakthrough",
content_text="Researchers have achieved a new milestone in quantum supremacy...",
source="Example Domain News",
timestamp=datetime.now(),
relevance_score=9,
summary_ru="Исследователи достигли нового рубежа в квантовом превосходстве.",
anomalies_detected=["Quantum supremacy", "Room temperature superconductors"],
category="Science"
)
@pytest.fixture
def mock_storage(mock_item):
storage = AsyncMock()
storage.search.return_value = [mock_item]
storage.get_by_id.return_value = mock_item
storage.get_stats.return_value = {"total": 1, "AI": 1}
return storage
@pytest.fixture
def allowed_chat_id():
return "123456789"
@pytest.fixture
def router(mock_storage, allowed_chat_id):
return get_router(mock_storage, allowed_chat_id)
def get_handler(router, callback_name):
for handler in router.message.handlers:
if handler.callback.__name__ == callback_name:
return handler.callback
raise ValueError(f"Handler {callback_name} not found")
def get_callback_handler(router, callback_name):
for handler in router.callback_query.handlers:
if handler.callback.__name__ == callback_name:
return handler.callback
raise ValueError(f"Handler {callback_name} not found")
@pytest.mark.asyncio
async def test_command_start_handler(router, allowed_chat_id):
handler = get_handler(router, "command_start_handler")
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.from_user = MagicMock()
message.from_user.full_name = "Test User"
message.answer = AsyncMock()
await handler(message)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Welcome" in args[0] or "Trend-Scout" in args[0]
@pytest.mark.asyncio
async def test_command_help_handler(router, allowed_chat_id):
handler = get_handler(router, "command_help_handler")
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
await handler(message)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "/start" in args[0]
assert "/latest" in args[0]
@pytest.mark.asyncio
async def test_command_latest_handler(router, mock_storage, allowed_chat_id):
handler = get_handler(router, "command_latest_handler")
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
command = CommandObject(prefix="/", command="latest", args=None)
await handler(message=message, command=command)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Latest news:" in args[0]
assert "reply_markup" in kwargs
assert isinstance(kwargs["reply_markup"], InlineKeyboardMarkup)
assert len(kwargs["reply_markup"].inline_keyboard) == 1
@pytest.mark.asyncio
async def test_command_search_handler(router, mock_storage, allowed_chat_id):
handler = get_handler(router, "command_search_handler")
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
command = CommandObject(prefix="/", command="search", args="quantum")
await handler(message=message, command=command)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Search results:" in args[0]
assert "reply_markup" in kwargs
mock_storage.search.assert_called_once_with(query="quantum", limit=10)
@pytest.mark.asyncio
async def test_detail_callback_handler(router, mock_storage, mock_item):
handler = get_callback_handler(router, "detail_callback_handler")
callback = AsyncMock(spec=CallbackQuery)
item_id = str(uuid.uuid5(uuid.NAMESPACE_URL, mock_item.url))
callback.data = f"detail:{item_id}"
callback.message = AsyncMock()
callback.message.answer = AsyncMock()
callback.answer = AsyncMock()
await handler(callback)
mock_storage.get_by_id.assert_called_once_with(item_id)
callback.message.answer.assert_called_once()
args, kwargs = callback.message.answer.call_args
assert mock_item.title in args[0]
assert mock_item.summary_ru in args[0]
callback.answer.assert_called_once()
@pytest.mark.asyncio
async def test_command_stats_handler(router, mock_storage, allowed_chat_id):
handler = get_handler(router, "command_stats_handler")
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
await handler(message=message)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Database Statistics" in args[0]
@pytest.mark.asyncio
async def test_access_middleware_allowed(allowed_chat_id):
middleware = AccessMiddleware(allowed_chat_id)
handler = AsyncMock()
event = MagicMock(spec=Message)
event.chat = MagicMock()
event.chat.id = int(allowed_chat_id)
event.answer = AsyncMock()
data = {}
await middleware(handler, event, data)
handler.assert_called_once_with(event, data)
event.answer.assert_not_called()
@pytest.mark.asyncio
async def test_access_middleware_denied(allowed_chat_id):
middleware = AccessMiddleware(allowed_chat_id)
handler = AsyncMock()
event = MagicMock(spec=Message)
event.chat = MagicMock()
event.chat.id = 999999999 # Different ID
event.answer = AsyncMock()
data = {}
await middleware(handler, event, data)
handler.assert_not_called()
event.answer.assert_called_once_with("Access Denied")