109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
"""
|
||
Тесты для helper_bot.middlewares.rate_limit_middleware.
|
||
"""
|
||
|
||
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
||
import pytest
|
||
from aiogram.types import CallbackQuery, Message, Update
|
||
|
||
from helper_bot.middlewares.rate_limit_middleware import RateLimitMiddleware
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestRateLimitMiddleware:
|
||
"""Тесты для RateLimitMiddleware."""
|
||
|
||
@pytest.fixture
|
||
def middleware(self):
|
||
"""Экземпляр middleware."""
|
||
return RateLimitMiddleware()
|
||
|
||
@pytest.fixture
|
||
def mock_handler(self):
|
||
"""Мок handler."""
|
||
return AsyncMock(return_value="handler_result")
|
||
|
||
async def test_event_with_message_calls_rate_limiter(
|
||
self, middleware, mock_handler
|
||
):
|
||
"""При событии с message вызывается rate_limiter.send_with_rate_limit."""
|
||
event = MagicMock(spec=Message)
|
||
event.message = None
|
||
event.chat = MagicMock()
|
||
event.chat.id = 12345
|
||
data = {}
|
||
|
||
with patch.object(
|
||
middleware.rate_limiter,
|
||
"send_with_rate_limit",
|
||
new_callable=AsyncMock,
|
||
return_value="rate_limited_result",
|
||
) as mock_send:
|
||
result = await middleware(mock_handler, event, data)
|
||
|
||
mock_send.assert_called_once()
|
||
call_args = mock_send.call_args
|
||
assert call_args[0][1] == 12345 # chat_id
|
||
# Вызываем переданный rate_limited_handler
|
||
await call_args[0][0]()
|
||
mock_handler.assert_called_once_with(event, data)
|
||
assert result == "rate_limited_result"
|
||
|
||
async def test_update_with_message_calls_rate_limiter(
|
||
self, middleware, mock_handler
|
||
):
|
||
"""При Update с message извлекается chat_id и вызывается rate_limiter."""
|
||
message = MagicMock(spec=Message)
|
||
message.chat = MagicMock()
|
||
message.chat.id = 99999
|
||
event = MagicMock(spec=Update)
|
||
event.message = message
|
||
data = {}
|
||
|
||
with patch.object(
|
||
middleware.rate_limiter,
|
||
"send_with_rate_limit",
|
||
new_callable=AsyncMock,
|
||
return_value="ok",
|
||
) as mock_send:
|
||
await middleware(mock_handler, event, data)
|
||
|
||
mock_send.assert_called_once()
|
||
assert mock_send.call_args[0][1] == 99999
|
||
|
||
async def test_event_without_message_calls_handler_directly(
|
||
self, middleware, mock_handler
|
||
):
|
||
"""При событии без message (например CallbackQuery) handler вызывается напрямую."""
|
||
event = MagicMock(spec=CallbackQuery)
|
||
event.message = None
|
||
data = {}
|
||
|
||
result = await middleware(mock_handler, event, data)
|
||
|
||
mock_handler.assert_called_once_with(event, data)
|
||
assert result == "handler_result"
|
||
|
||
async def test_exception_from_handler_propagates(self, middleware, mock_handler):
|
||
"""Исключение из handler пробрасывается через rate_limiter."""
|
||
event = MagicMock(spec=Message)
|
||
event.chat = MagicMock()
|
||
event.chat.id = 1
|
||
data = {}
|
||
mock_handler.side_effect = ValueError("test error")
|
||
|
||
with patch.object(
|
||
middleware.rate_limiter,
|
||
"send_with_rate_limit",
|
||
new_callable=AsyncMock,
|
||
) as mock_send:
|
||
|
||
async def call_passed_handler(inner_handler, chat_id):
|
||
return await inner_handler()
|
||
|
||
mock_send.side_effect = call_passed_handler
|
||
with pytest.raises(ValueError, match="test error"):
|
||
await middleware(mock_handler, event, data)
|