testingСредний15 минут
Performance testing с pytest-benchmark
Быстрый старт с pytest-benchmark: ставим рядом с функциональными тестами, заводим бюджет времени и сохраняем baseline в CI.
#pytest#performance#benchmark#testing
Оглавление
Performance testing с pytest-benchmark
Этот материал дополняет курс "Pytest: Борьба с flaky-тестами и race conditions", но не является его частью. Performance testing — отдельная дисциплина, которая требует своего подхода и инструментов.
Быстрый старт
Performance testing != Flaky testing. Это отдельная тема, но если вы хотите быстро прикрутить бенчмарки к вашему проекту:
pip install pytest-benchmarkБазовый пример
# tests/perf/test_serialization.py
import pytest
def test_order_serializer_speed(benchmark, sample_orders):
"""Тестируем скорость сериализации заказов"""
result = benchmark(serialize_orders, sample_orders)
# Можно установить бюджет времени
assert benchmark.stats['mean'] < 0.05 # 50ms максимумЗапуск бенчмарков
# Запустить только бенчмарки
pytest tests/perf --benchmark-only
# С прогревом (warmup)
pytest tests/perf --benchmark-only --benchmark-warmup=on
# Сохранить baseline
pytest tests/perf --benchmark-only --benchmark-save=baseline
# Сравнить с baseline
pytest tests/perf --benchmark-only --benchmark-compare=baselineBest practices
1. Отдельная директория для бенчмарков
tests/
perf/ # Performance tests
test_api.py
test_db.py
functional/ # Functional tests
test_orders.py
2. Используйте маркеры
import pytest
@pytest.mark.perf
def test_database_query_speed(benchmark, db):
benchmark(db.query, "SELECT * FROM orders")Запуск:
pytest -m perf --benchmark-only3. Фиксированное железо
Бенчмарки чувствительны к нагрузке:
- Запускайте на выделенных CI-раннерах
- Отключайте другие процессы
- Используйте одну и ту же машину для сравнения
4. Установите бюджеты времени
def test_api_response_time(benchmark, client):
response = benchmark(client.get, "/api/orders")
# Жёсткие требования к производительности
assert benchmark.stats['mean'] < 0.1 # 100ms среднее
assert benchmark.stats['max'] < 0.5 # 500ms максимумИнтеграция в CI
# .gitlab-ci.yml
performance:
stage: test
tags:
- performance # Выделенный раннер
script:
- pip install -e '.[test,perf]'
- pytest tests/perf --benchmark-only --benchmark-save=ci-${CI_COMMIT_SHA}
- pytest tests/perf --benchmark-compare=baseline --benchmark-compare-fail=mean:10%
only:
- master
- merge_requestsЧто НЕ надо делать
❌ Не смешивайте бенчмарки с функциональными тестами
# Плохо: в одном тесте функциональность И производительность
def test_order_creation(db):
start = time.time()
order = create_order(db, {...})
assert time.time() - start < 0.1 # ❌
assert order.status == "pending"✅ Разделяйте тесты:
# Функциональный тест
def test_order_creation(db):
order = create_order(db, {...})
assert order.status == "pending"
# Performance тест
@pytest.mark.perf
def test_order_creation_speed(benchmark, db):
benchmark(create_order, db, {...})Продвинутые возможности
Параметризация бенчмарков
@pytest.mark.parametrize("size", [10, 100, 1000, 10000])
def test_serialization_scaling(benchmark, size):
data = generate_orders(size)
benchmark(serialize_orders, data)Группировка результатов
@pytest.mark.benchmark(group="serialization")
def test_json_serialization(benchmark, orders):
benchmark(json.dumps, orders)
@pytest.mark.benchmark(group="serialization")
def test_msgpack_serialization(benchmark, orders):
benchmark(msgpack.packb, orders)Когда использовать pytest-benchmark
✅ Хорошо подходит для:
- Unit-тесты критичных функций
- Регрессионное тестирование производительности
- Сравнение разных реализаций
- CI/CD проверки
❌ Не подходит для:
- Load testing (используйте Locust, k6)
- Stress testing
- Распределённого тестирования
- Production monitoring
Альтернативы
Для других задач performance testing используйте:
- Load testing: Locust, k6, JMeter
- Profiling: cProfile, py-spy, memory_profiler
- APM: New Relic, DataDog, Sentry Performance