Обновлен Python до версии 3.11.9 и изменены зависимости в Dockerfile и pyproject.toml. Удалены устаревшие файлы RATE_LIMITING_SOLUTION.md и тесты для rate limiting.

Обновлены пути к библиотекам в Dockerfile для соответствия новой версии Python.
Исправлены все тесты, теперь все проходят
This commit is contained in:
2026-01-25 16:07:27 +03:00
parent 5a90591564
commit d2d7c83575
21 changed files with 2324 additions and 409 deletions

197
.cursor/rules/testing.md Normal file
View File

@@ -0,0 +1,197 @@
---
description: "Паттерны тестирования, структура тестов и использование pytest"
globs: ["tests/**/*.py", "test_*.py"]
---
# Паттерны тестирования
## Структура тестов
Тесты находятся в директории `tests/` и используют pytest:
```
tests/
├── conftest.py # Общие фикстуры
├── conftest_*.py # Специализированные фикстуры
├── mocks.py # Моки и заглушки
└── test_*.py # Тестовые файлы
```
## Конфигурация pytest
Настройки в `pyproject.toml`:
- `asyncio-mode=auto` - автоматический режим для async тестов
- Маркеры: `asyncio`, `slow`, `integration`, `unit`
- Фильтрация предупреждений
## Структура теста
```python
import pytest
from database.async_db import AsyncBotDB
from database.repositories.user_repository import UserRepository
@pytest.mark.asyncio
async def test_user_repository_add_user(db_path):
"""Тест добавления пользователя."""
# Arrange
repo = UserRepository(db_path)
user = User(user_id=123, full_name="Test User")
# Act
await repo.add_user(user)
# Assert
result = await repo.get_user_by_id(123)
assert result is not None
assert result.full_name == "Test User"
```
## Фикстуры
### Общие фикстуры (conftest.py)
```python
import pytest
import tempfile
import os
@pytest.fixture
def db_path():
"""Создает временный файл БД для тестов."""
fd, path = tempfile.mkstemp(suffix='.db')
os.close(fd)
yield path
os.unlink(path)
@pytest.fixture
async def async_db(db_path):
"""Создает AsyncBotDB для тестов."""
db = AsyncBotDB(db_path)
await db.create_tables()
yield db
```
### Использование фикстур
```python
@pytest.mark.asyncio
async def test_something(async_db):
# async_db уже инициализирован
result = await async_db.some_method()
assert result is not None
```
## Моки
Используйте `mocks.py` для общих моков:
```python
from unittest.mock import AsyncMock, MagicMock
def mock_bot():
"""Создает мок бота."""
bot = MagicMock()
bot.send_message = AsyncMock()
return bot
```
## Маркеры
Используйте маркеры для категоризации тестов:
```python
@pytest.mark.unit
@pytest.mark.asyncio
async def test_unit_test():
"""Быстрый unit тест."""
...
@pytest.mark.integration
@pytest.mark.asyncio
async def test_integration_test():
"""Медленный integration тест."""
...
@pytest.mark.slow
@pytest.mark.asyncio
async def test_slow_test():
"""Медленный тест."""
...
```
Запуск с фильтрацией:
```bash
pytest -m "not slow" # Пропустить медленные тесты
pytest -m unit # Только unit тесты
```
## Тестирование Handlers
```python
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from unittest.mock import AsyncMock
@pytest.mark.asyncio
async def test_handler(mock_bot, mock_message):
"""Тест handler."""
# Arrange
dp = Dispatcher(storage=MemoryStorage())
# Регистрация handler
...
# Act
await dp.feed_update(mock_update)
# Assert
mock_bot.send_message.assert_called_once()
```
## Тестирование Services
```python
@pytest.mark.asyncio
async def test_service_method(async_db):
"""Тест метода сервиса."""
service = SomeService(async_db, {})
result = await service.do_something()
assert result is not None
```
## Тестирование Repositories
```python
@pytest.mark.asyncio
async def test_repository_crud(db_path):
"""Тест CRUD операций репозитория."""
repo = SomeRepository(db_path)
await repo.create_tables()
# Create
entity = SomeEntity(...)
await repo.add(entity)
# Read
result = await repo.get_by_id(entity.id)
assert result is not None
# Update
entity.field = "new_value"
await repo.update(entity)
# Delete
await repo.delete(entity.id)
result = await repo.get_by_id(entity.id)
assert result is None
```
## Best Practices
1. **Используйте фикстуры** для переиспользования setup/teardown
2. **Изолируйте тесты** - каждый тест должен быть независимым
3. **Используйте временные БД** для тестов репозиториев
4. **Мокируйте внешние зависимости** (API, файловая система)
5. **Пишите понятные имена тестов** - они должны описывать что тестируется
6. **Используйте Arrange-Act-Assert** паттерн
7. **Тестируйте граничные случаи** и ошибки