118 lines
3.7 KiB
Markdown
118 lines
3.7 KiB
Markdown
# Стандарты тестирования
|
|
|
|
## Философия
|
|
|
|
**Код без тестов — это не код, а предложение.** Если функцию нельзя проверить — она либо не нужна, либо её нужно переписать.
|
|
|
|
---
|
|
|
|
## Пирамида тестов
|
|
|
|
```
|
|
/\ E2E (10%): сквозные сценарии
|
|
/ \
|
|
/ \
|
|
/──────\ Integration (20%): API, БД, внешние сервисы
|
|
/ \
|
|
/──────────\ Unit (70%): изолированные модули
|
|
/ \
|
|
```
|
|
|
|
---
|
|
|
|
## Типы тестов
|
|
|
|
### Unit-тесты (`tests/unit/`)
|
|
- Тестируют один класс/функцию в изоляции
|
|
- Внешние зависимости мокаются
|
|
- Быстрые (миллисекунды)
|
|
- Пример: тест сервиса с mocked репозиторием
|
|
|
|
```python
|
|
async def test_idea_service_create():
|
|
service = IdeaService(mock_db)
|
|
idea = await service.create(user_id="1", title="Test", content="Content")
|
|
assert idea.title == "Test"
|
|
assert idea.status == "draft"
|
|
```
|
|
|
|
### Integration-тесты (`tests/integration/`)
|
|
- Тестируют взаимодействие компонентов
|
|
- Используют реальную БД (SQLite в памяти)
|
|
- Проверяют API endpoints, БД запросы
|
|
- Пример: тест регистрации пользователя
|
|
|
|
```python
|
|
async def test_register_user(async_client):
|
|
response = await async_client.post("/api/v1/auth/register", json={
|
|
"username": "test",
|
|
"email": "test@test.com",
|
|
"password": "secret123",
|
|
})
|
|
assert response.status_code == 201
|
|
data = response.json()
|
|
assert "access_token" in data
|
|
```
|
|
|
|
### Smoke-тесты (`tests/smoke/`)
|
|
- Минимум 1 тест на каждый endpoint
|
|
- Проверяют что endpoint отвечает и возвращает корректный статус
|
|
- Быстрая проверка здоровья системы
|
|
|
|
```python
|
|
async def test_health_endpoint(async_client):
|
|
response = await async_client.get("/health")
|
|
assert response.status_code == 200
|
|
assert response.json()["status"] == "healthy"
|
|
```
|
|
|
|
---
|
|
|
|
## Покрытие
|
|
|
|
- **Общее покрытие:** > 80%
|
|
- **Критический код (auth, security, payments):** 100%
|
|
- **Новый код:** без тестов не принимается в PR
|
|
|
|
---
|
|
|
|
## Что тестировать
|
|
|
|
### Обязательно (9 сценариев для каждого endpoint)
|
|
|
|
1. **Missing field** → 422
|
|
2. **Wrong type** → 422
|
|
3. **Expired/invalid token** → 401
|
|
4. **Wrong permissions** → 403
|
|
5. **Not found** → 404
|
|
6. **Conflict** → 409
|
|
7. **Success** → 200/201
|
|
8. **Rate limit** → 429 (если реализован)
|
|
9. **Idempotency** → тот же результат при повторе
|
|
|
|
### Для каждого сервиса
|
|
- Успешное выполнение
|
|
- Ошибка валидации
|
|
- Ошибка БД
|
|
- Граничные случаи (пустой список, null, максимальная длина)
|
|
|
|
---
|
|
|
|
## Конфигурация pytest
|
|
|
|
```ini
|
|
# pyproject.toml или pytest.ini
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
```
|
|
|
|
---
|
|
|
|
## [ASK] Вопросы по тестированию
|
|
|
|
- Нужен ли coverage порог в CI? (рекомендуется 80%)
|
|
- Использовать ли vcrpy для записи ответов внешних API? (да, для AI провайдеров)
|
|
- Нужны ли performance-тесты? (да, для критических endpoint'ов)
|