Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Production CI/CD и quality gates
production_ci_cd

Production CI/CD и quality gates

Стратегия маркеров: @pytest.mark.slow, @pytest.mark.integration. GitHub Actions: Docker Compose, кеширование образов. pytest-xdist параллельный запуск. Matrix-стратегия: разные версии PostgreSQL. Coverage thresholds и quality gates

Production CI/CD должен быть быстрым (параллельный запуск), надёжным (quality gates) и гибким (тесты на разных версиях БД).

Цель: Настроить production-ready CI/CD pipeline с pytest-xdist, Docker и quality gates.

Стратегия маркеров

Проблема: все тесты в одной куче

# Все тесты вместе — медленно! pytest tests/ # Результат: # 500 unit tests (fast) + 50 integration tests (slow) = 10 minutes

Решение: разделить по типам

# tests/test_users_unit.py import pytest @pytest.mark.unit def test_user_validation(): """Быстрый unit тест""" # ... pass # tests/test_users_integration.py @pytest.mark.integration @pytest.mark.slow def test_user_creation_db(db_connection): """Медленный integration тест""" # ... pass

pytest.ini конфигурация

# pytest.ini [pytest] markers = unit: Unit tests (fast, no external dependencies) integration: Integration tests (slow, require DB/API) slow: Slow tests (>1s per test) smoke: Smoke tests (critical functionality)

Запуск по маркерам

# Только unit (быстрые) pytest -m unit # Только integration pytest -m integration # Исключить slow pytest -m "not slow" # unit ИЛИ smoke pytest -m "unit or smoke" # integration И медленные pytest -m "integration and slow"

GitHub Actions: базовый CI

.github/workflows/tests.yml

name: Tests on: push: branches: [main, develop] pull_request: branches: [main] jobs: unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | pip install -r requirements.txt pip install pytest pytest-cov - name: Run unit tests run: | pytest -m unit --cov=src --cov-report=xml - name: Upload coverage uses: codecov/codecov-action@v3 with: file: ./coverage.xml integration-tests: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | pip install -r requirements.txt pip install pytest - name: Run integration tests env: DB_HOST: localhost DB_PORT: 5432 DB_USER: testuser DB_PASSWORD: testpass DB_NAME: testdb run: | pytest -m integration -v

pytest-xdist: параллельный запуск

Установка

pip install pytest-xdist

Запуск на всех ядрах CPU

# Автоматическое определение количества ядер pytest -n auto # Конкретное количество workers pytest -n 4 # С маркерами pytest -m integration -n auto

GitHub Actions с pytest-xdist

# .github/workflows/tests.yml - name: Run integration tests (parallel) run: | pytest -m integration -n auto -v

Проблема: shared state между тестами

# ❌ Плохо: глобальное состояние cache = {} def test_cache_write(): cache["key"] = "value" def test_cache_read(): assert cache["key"] == "value" # ❌ Упадёт при -n auto!

Решение: изоляция через фикстуры

# ✅ Хорошо: каждый тест изолирован @pytest.fixture def cache(): return {} def test_cache_write(cache): cache["key"] = "value" def test_cache_read(cache): # Новый cache для каждого теста cache["key"] = "value" assert cache["key"] == "value"

Coverage thresholds: quality gates

pytest.ini с threshold

# pytest.ini [pytest] addopts = --cov=src --cov-report=term-missing --cov-report=xml --cov-fail-under=80

--cov-fail-under=80 — тесты упадут если coverage < 80%

GitHub Actions с quality gate

- name: Run tests with coverage run: | pytest -m unit --cov=src --cov-fail-under=80 - name: Check coverage report if: failure() run: | echo "❌ Coverage is below 80%" exit 1

Matrix strategy: разные версии PostgreSQL

# .github/workflows/tests.yml jobs: integration-tests: runs-on: ubuntu-latest strategy: matrix: postgres-version: [12, 13, 14, 15, 16] services: postgres: image: postgres:${{ matrix.postgres-version }} env: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb ports: - 5432:5432 steps: - name: Run tests on PostgreSQL ${{ matrix.postgres-version }} run: | pytest -m integration -v

✅ Тесты запустятся на всех 5 версиях PostgreSQL!

Docker кеширование

Проблема: каждый раз собирать Docker образ (медленно)

# ❌ Медленно: 5 минут на сборку каждый раз - name: Build Docker image run: docker build -t myapp . - name: Run tests run: docker-compose up --abort-on-container-exit

Решение: кешировать Docker layers

- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Cache Docker layers uses: actions/cache@v3 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ hashFiles('**/Dockerfile') }} restore-keys: | ${{ runner.os }}-buildx- - name: Build and cache uses: docker/build-push-action@v5 with: context: . cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new tags: myapp:latest load: true - name: Run tests run: docker-compose up --abort-on-container-exit

Flaky tests detection

Проблема: тесты падают случайно (race conditions, таймауты)

# Flaky test: иногда проходит, иногда падает def test_api_response_time(): response = requests.get("http://api/endpoint") assert response.elapsed.total_seconds() < 1.0 # ❌ Иногда 1.1s!

pytest-rerunfailures

pip install pytest-rerunfailures
# Перезапустить упавшие тесты 3 раза pytest --reruns 3

GitHub Actions с reruns

- name: Run tests with reruns run: | pytest -m integration --reruns 3 --reruns-delay 2 -v

Полный production pipeline

# .github/workflows/ci.yml name: CI Pipeline on: push: branches: [main] pull_request: jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install ruff mypy - run: ruff check . - run: mypy src/ unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install -r requirements.txt pytest pytest-cov pytest-xdist - run: pytest -m unit -n auto --cov=src --cov-fail-under=80 -v integration-tests: runs-on: ubuntu-latest needs: unit-tests strategy: matrix: postgres-version: [15, 16] services: postgres: image: postgres:${{ matrix.postgres-version }} env: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb ports: - 5432:5432 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install -r requirements.txt pytest pytest-xdist pytest-rerunfailures - run: pytest -m integration -n auto --reruns 2 -v quality-gate: runs-on: ubuntu-latest needs: [lint, unit-tests, integration-tests] if: always() steps: - name: Check all jobs passed run: | if [[ "${{ needs.lint.result }}" == "failure" ]] || \ [[ "${{ needs.unit-tests.result }}" == "failure" ]] || \ [[ "${{ needs.integration-tests.result }}" == "failure" ]]; then echo "❌ Quality gate FAILED" exit 1 fi echo "✅ Quality gate PASSED"

Проверьте свои знания

Вопросы ещё не добавлены

Вопросы для этой подтемы ещё не добавлены.