3.7 KiB
3.7 KiB
Стандарты тестирования
Философия
Код без тестов — это не код, а предложение. Если функцию нельзя проверить — она либо не нужна, либо её нужно переписать.
Пирамида тестов
/\ E2E (10%): сквозные сценарии
/ \
/ \
/──────\ Integration (20%): API, БД, внешние сервисы
/ \
/──────────\ Unit (70%): изолированные модули
/ \
Типы тестов
Unit-тесты (tests/unit/)
- Тестируют один класс/функцию в изоляции
- Внешние зависимости мокаются
- Быстрые (миллисекунды)
- Пример: тест сервиса с mocked репозиторием
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, БД запросы
- Пример: тест регистрации пользователя
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 отвечает и возвращает корректный статус
- Быстрая проверка здоровья системы
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)
- Missing field → 422
- Wrong type → 422
- Expired/invalid token → 401
- Wrong permissions → 403
- Not found → 404
- Conflict → 409
- Success → 200/201
- Rate limit → 429 (если реализован)
- Idempotency → тот же результат при повторе
Для каждого сервиса
- Успешное выполнение
- Ошибка валидации
- Ошибка БД
- Граничные случаи (пустой список, null, максимальная длина)
Конфигурация pytest
# 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'ов)