← Назад к вопросам
Как правильно построить процесс QA для проекта?
2.4 Senior🔥 121 комментариев
#DevOps и инфраструктура#Архитектура и паттерны#Тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Процесс QA: построение надёжной системы контроля качества
QA — это не только тестирование. Это цикл обеспечения качества, начинающийся с планирования и заканчивающийся мониторингом в production.
1. Пирамида тестирования
Правильное соотношение тестов:
E2E тесты (10%)
/ \
/ \
/ Integration \
/ тесты (20%) \
/ \
/_____ Unit тесты _____\
(70%)
Объяснение:
- Unit тесты (70%): Быстрые, дешёвые, тестируют отдельные функции/методы
- Integration тесты (20%): Тестируют взаимодействие компонентов (API с БД, сервисы между собой)
- E2E тесты (10%): Дорогие, медленные, тестируют полный пользовательский flow
Пример структуры:
# tests/unit/
# └── test_calculate_price.py
# └── test_validate_email.py
# └── test_user_repository.py
# tests/integration/
# └── test_user_api.py
# └── test_order_workflow.py
# └── test_payment_integration.py
# tests/e2e/
# └── test_user_registration_flow.py
# └── test_checkout_process.py
2. Continuous Integration (CI) pipeline
Автоматический запуск тестов при каждом commit:
# .github/workflows/tests.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Lint with ruff
run: |
ruff check .
ruff format --check .
- name: Type check with mypy
run: mypy .
- name: Run unit tests
run: pytest tests/unit -v --cov=app --cov-report=xml
- name: Run integration tests
run: pytest tests/integration -v
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml
- name: Run E2E tests (if changed)
if: contains(github.event.pull_request.files, 'frontend') || contains(github.event.pull_request.files, 'api')
run: pytest tests/e2e -v
3. Стратегия покрытия кода
Минимум 80-90% покрытия для critical path:
# Проверить покрытие
pytest --cov=app --cov-report=html
# Смотреть результат
open htmlcov/index.html
Правила покрытия:
# КРИТИЧНЫЙ КОД (должен быть покрыт на 100%)
def process_payment(amount: float, card_token: str) -> bool:
"""Обработка платежа — CRITICAL!"""
if amount <= 0:
raise ValueError("Amount must be positive")
# ...
return True
# ВАЖНЫЙ КОД (80-90% покрытие)
def calculate_discount(amount: float, customer_type: str) -> float:
"""Расчёт скидки"""
if customer_type == 'premium':
return amount * 0.2
elif customer_type == 'regular':
return amount * 0.1
return 0
# УТИЛИТЫ (70% покрытие)
def format_phone(phone: str) -> str:
"""Форматирование номера телефона"""
return phone.replace('-', '').replace(' ', '')
4. Виды тестов в Python
Unit тест (pytest):
# tests/unit/test_calculator.py
import pytest
from app.calculator import calculate_price
def test_calculate_price_with_discount():
result = calculate_price(100, discount=0.2)
assert result == 80
def test_calculate_price_without_discount():
result = calculate_price(100)
assert result == 100
def test_calculate_price_invalid_amount():
with pytest.raises(ValueError):
calculate_price(-100)
Integration тест (с мокированием):
# tests/integration/test_user_service.py
import pytest
from unittest.mock import Mock, patch
from app.services.user_service import UserService
from app.repositories.user_repository import UserRepository
@pytest.fixture
def user_service():
mock_repo = Mock(spec=UserRepository)
return UserService(user_repository=mock_repo)
def test_create_user_sends_email(user_service):
# Arrange
user_service.user_repository.save = Mock()
user_service.email_service = Mock()
# Act
user_service.create_user('john@example.com', 'John')
# Assert
user_service.user_repository.save.assert_called_once()
user_service.email_service.send_welcome.assert_called_once()
E2E тест (Playwright):
# tests/e2e/test_registration_flow.py
import pytest
from playwright.sync_api import Page
@pytest.fixture(scope="function")
def page():
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
yield p.chromium.launch().new_page()
def test_user_registration_flow(page: Page):
# Arrange
page.goto('http://localhost:3000/register')
# Act
page.fill('[name="email"]', 'test@example.com')
page.fill('[name="password"]', 'SecurePass123')
page.click('button[type="submit"]')
# Assert
page.wait_for_url('http://localhost:3000/dashboard')
assert page.is_visible(':text("Welcome, test@example.com")')
5. Локальное тестирование перед push
Pre-commit hook — тесты перед каждым commit:
# .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "Running pre-commit checks..."
# Lint
ruff check . || exit 1
ruff format --check . || exit 1
# Type check
mypy . || exit 1
# Unit tests
pytest tests/unit -q || exit 1
echo "All checks passed!"
Установка:
npm install husky --save-dev
npx husky install
npx husky add .husky/pre-commit "bash scripts/pre-commit.sh"
6. Staging окружение
Deploy на staging для тестирования перед production:
# docker-compose.staging.yml
version: '3.9'
services:
app:
image: myapp:${VERSION}
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://user:pass@db-staging:5432/app_staging
DEBUG: 'false'
LOG_LEVEL: 'info'
db-staging:
image: postgres:15
environment:
POSTGRES_DB: app_staging
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- staging_db:/var/lib/postgresql/data
volumes:
staging_db:
Smoke тесты на staging:
# tests/smoke/test_staging.py
import os
import requests
STAGING_URL = os.getenv('STAGING_URL', 'http://staging.example.com')
def test_api_is_healthy():
response = requests.get(f'{STAGING_URL}/health')
assert response.status_code == 200
def test_database_is_accessible():
response = requests.get(f'{STAGING_URL}/api/v1/users')
assert response.status_code == 200
assert isinstance(response.json(), list)
7. Мониторинг в production
Error tracking (Sentry):
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
sentry_sdk.init(
dsn=os.getenv('SENTRY_DSN'),
integrations=[FastApiIntegration()],
traces_sample_rate=0.1, # Логируем 10% запросов
environment=os.getenv('ENVIRONMENT', 'production')
)
# Автоматически отправляет все исключения в Sentry
from fastapi import FastAPI
app = FastAPI()
Логирование:
import logging
from pythonjsonlogger import jsonlogger
logger = logging.getLogger(__name__)
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter()
logHandler.setFormatter(formatter)
logger.addHandler(logHandler)
@app.get('/api/v1/users')
async def get_users():
logger.info('Fetching users', extra={'user_count': 100})
return {}
8. Чеклист QA процесса
Для каждого feature:
- Unit тесты написаны (>80% coverage)
- Integration тесты написаны
- Code review пройден
- Тесты проходят в CI/CD
- Развёрнуто на staging
- Smoke тесты пройдены
- Задокументировано (если нужно)
- Merged в main
Для каждого release:
- Smoke тесты на production
- Мониторинг ошибок
- Проверка логов
- Проверка метрик (response time, CPU, memory)
- Rollback план готов
9. Рекомендуемые инструменты
| Инструмент | Задача | Пример |
|---|---|---|
| pytest | Unit/Integration тесты | pytest tests/ -v |
| pytest-cov | Coverage | pytest --cov=app |
| Mock/patch | Мокирование зависимостей | Mock(spec=Repository) |
| Playwright | E2E тесты | pytest tests/e2e/ |
| ruff | Linting | ruff check . |
| mypy | Type checking | mypy . |
| GitHub Actions | CI/CD pipeline | .github/workflows/ |
| Sentry | Error tracking | sentry.io |
| Prometheus | Метрики | prometheus.io |
| ELK Stack | Логирование | elasticsearch + kibana |
Итог
Правильный процесс QA:
- Unit тесты — разработчик пишет (TDD)
- Integration тесты — взаимодействие компонентов
- CI pipeline — автоматический запуск при push
- Code review — проверка кода
- Staging deploy — smoke тесты
- E2E тесты — полный user flow
- Production — мониторинг и логирование
- Постоянное улучшение — анализ инцидентов
Это обеспечит надёжность и качество вашего проекта!