Гид по технологиям

Pytest: быстрое руководство по тестированию Python

6 min read Тестирование Обновлено 06 Dec 2025
Pytest: руководство по тестированию Python
Pytest: руководство по тестированию Python

Код на экране компьютера, демонстрирующий тестирование на Python

Изображение: пример редактора кода с тестами и запуском тестов в терминале

Тестирование — неотъемлемая часть разработки. Оно обнаруживает ошибки на ранних стадиях, повышает надёжность и упрощает рефакторинг. Pytest позволяет писать компактные, читаемые тесты, которые масштабируются вместе с проектом.

Что вы получите из этого руководства

  • Пошаговая установка и запуск pytest
  • Примеры тестов: простые, параметризованные, для исключений
  • Лучшие практики организации тестов и настройки конфигурации
  • Чеклист обязанностей для ролей: разработчик, тестировщик, DevOps
  • Отладка неудачных тестов и сценарии отказа
  • Шаблоны, критерии приёмки и короткая шпаргалка команд

Установка и виртуальное окружение

Важно: используйте виртуальное окружение, чтобы зависимости тестов не конфликтовали с глобальными пакетами.

Создайте виртуальное окружение в каталоге проекта (например, tests):

python -m venv tests

Активируйте окружение на macOS / Linux:

source tests/bin/activate

На Windows (PowerShell/CMD):

tests\Scripts\activate

Установите pytest через pip:

pip install pytest

Проверьте версию pytest:

pytest --version

Если команда вернула номер версии — установка прошла успешно.

Примечание: при использовании poetry, pipenv или других инструментов управления зависимостями следуйте их рекомендациям для создания изолированных окружений.

Первый тест: функция сложения

Рассмотрим простую функцию, складывающую два числа:

def add_numbers(a, b):
    return a + b

Критичные случаи: нечисловые входы (None, строки), большой диапазон значений, плавающие точки.

Создайте файл теста, например test_math.py, и напишите базовый тест:

def test_add_numbers():
    assert add_numbers(2, 3) == 5
    assert add_numbers(-1, 1) == 0
    assert add_numbers(0, 0) == 0

Объяснение: assert сравнивает реальный результат с ожидаемым. Pytest автоматически обнаружит функции и файлы, начинающиеся с test_.

Запуск тестов

Перейдите в папку проекта и выполните:

pytest

Pytest выполнит все тесты и выведет результат. Если тесты не прошли, вы увидите трассировку и конкретные значения, которые привели к провалу.

Пример падения теста — неправильный ожидаемый результат:

def test_add_numbers():
    assert add_numbers(2, 3) == 6

Pytest покажет входные данные и фактическое значение, что облегчает диагностику.

Результат запуска pytest — пример вывода с провалившимся тестом

Изображение: окно терминала с подробным выводом ошибки теста

Проверка исключений с pytest.raises

Чтобы убедиться, что функция корректно реагирует на некорректные входы, используйте pytest.raises:

import pytest

def test_add_numbers_with_invalid_inputs():
    with pytest.raises(TypeError):
        add_numbers(None, 2)

Контекстный менеджер pytest.raises возвращает объект ExceptionInfo, позволяющий проверить сообщение исключения:

def test_add_numbers_with_invalid_inputs():
    with pytest.raises(TypeError) as exc_info:
        add_numbers(None, 2)

    assert exc_info.value.args[0] == "unsupported operand type(s) for +: 'NoneType' and 'int'"

Важно: проверка точного текста исключения полезна при специфических ошибках, но делает тесты хрупкими при изменении формулировки исключения. Лучше проверять тип исключения и ключевые слова сообщения.

Параметризованные тесты

Pytest.mark.parametrize позволяет запускать одну тест-функцию с набором входных данных. Это делает тесты компактнее и понятнее:

import pytest

@pytest.mark.parametrize("a,b,expected", [
    (2, 3, 5),
    (-1, 1, 0),
    (0, 0, 0),
])
def test_add_numbers(a, b, expected):
    assert add_numbers(a, b) == expected

Преимущества: сразу видно набор случаев, каждый случай считается отдельным тестом в выводе pytest.

Организация тестов и классы

Для группировки тестов используйте модули и каталоги. Можно объединять тесты в классах — pytest обнаруживает классы, начинающиеся с Test:

class TestAddFunction:
    @pytest.mark.parametrize("a, b, expected", [
        (2, 3, 5),
        (-1, 1, 0),
        (0, 0, 0),
    ])
    def test_addition_with_numbers(self, a, b, expected):
        assert add_numbers(a, b) == expected

    def test_add_numbers_with_invalid_inputs(self):
        with pytest.raises(TypeError) as exc_info:
            add_numbers(None, 2)
        assert "NoneType" in exc_info.value.args[0]

Совет: тестовые классы не должны хранить состояние между тестами. Для общего состояния используйте фикстуры.

Fixtures: настройка и очистка

Фикstуры (fixtures) — способ подготовить состояние перед тестом и выполнить очистку после него. Коротко: фикстура — это функция, помеченная @pytest.fixture, которую вы передаёте в тест как аргумент.

Пример фикстуры:

import pytest

@pytest.fixture
def sample_data():
    data = {"a": 1, "b": 2}
    yield data
    # здесь можно очистить ресурсы

Использование:

def test_using_fixture(sample_data):
    assert sample_data["a"] + sample_data["b"] == 3

Фикстуры можно параметризовать, композировать и задавать область видимости (function, module, session).

Конфигурация pytest

Для настройки поведения pytest создайте файл pytest.ini или pyproject.toml с секцией [pytest]. Пример pytest.ini:

[pytest]
minversion = 6.0
addopts = -ra -q
testpaths = tests
python_files = test_*.py *_test.py

Опции addopts позволяют по умолчанию добавлять ключи командной строки (например, -q для краткого вывода).

Интеграция в CI

Часто pytest запускают в CI при каждом коммите. Пример простого конвейера (GitHub Actions):

name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.10'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      - name: Run tests
        run: |
          pytest

Важно: включайте покрытие (coverage) и артефакты тестов при необходимости, сохраняйте логи для отладки.

Отладка провалившихся тестов

Шаги для анализа:

  1. Прочитать сообщение об ошибке и трассировку. Pytest показывает входные данные и фактическое значение.
  2. Запустить только проблемный тест: pytest path::test_name -k pattern -q
  3. Добавить -s, чтобы видеть вывод print/логов: pytest -k test_name -s
  4. Использовать pdb для интерактивной отладки: pytest –pdb
  5. Проверить окружение: версии библиотек, переменные окружения, фикстуры.

Совет: пишите тесты маленькими и изолированными — это упрощает локализацию ошибки.

Когда тесты дают ложные срабатывания

Примеры причин:

  • Нестабильные внешние зависимости (сеть, базы данных) — используйте мокинг
  • Состояние, сохраняемое между тестами — используйте фикстуры с правильной областью видимости
  • Зависимость от времени — мокируйте время (freezegun или pytest-monkeypatch)

Альтернативы и когда pytest не подходит

Когда рассмотреть альтернативы:

  • unittest — встроенный модуль, лучше для простых проектов или при необходимости совместимости со старыми плагинами
  • nose2 — похож на pytest, но менее распространён

Pytest — выбор по умолчанию для большинства новых проектов благодаря удобству и сообществу.

Практическое руководство: чеклист для ролей

Чеклист разработчика:

  • Добавил/обновил тесты для нового кода
  • Тесты запускаются локально в виртуальном окружении
  • Не оставил print() и дебаг-код
  • Тесты покрывают пограничные случаи

Чеклист тестировщика:

  • Запустил весь набор тестов
  • Проверил параллельный запуск (pytest-xdist) при необходимости
  • Подготовил тестовые данные и фикстуры

Чеклист DevOps:

  • Интеграция в CI настроена и проходит
  • Артефакты тестового покрытия публикуются
  • Логи тестов сохраняются для расследования инцидентов

Критерии приёмки

  • Все новые и изменённые функции имеют тесты
  • Тесты проходят локально и в CI
  • Покрытие критичных модулей соответствует внутренним требованиям команды
  • Нет неустранимых предупреждений или временных зависимостей

Мини-методология для написания тестов

  1. Пишите тест до фиксации бага (TDD) либо сразу после реализации.
  2. Делайте тесты малыми и независимыми.
  3. Избегайте внешних влияний — мокируйте запросы и файловую систему.
  4. Используйте parametrization для наборов данных.
  5. Покрывайте как позитивные, так и негативные сценарии.

Примеры тест-кейсов для add_numbers

  • Позитивные: (2,3)=5, (-1,1)=0, (0,0)=0
  • Негативные: (None,2) -> TypeError
  • Граничные: большие целые, очень маленькие/большие float

Шпаргалка команд

  • Запуск всех тестов: pytest
  • Запуск конкретного файла: pytest tests/test_math.py
  • Запуск конкретного теста: pytest tests/test_math.py::test_add_numbers
  • Запуск с подробным выводом: pytest -v
  • Включить pdb при падении: pytest –pdb
  • Параллельный запуск: pytest -n auto (плагин pytest-xdist)

Безопасность и конфиденциальность

Не храните реальные секреты в тестовых данных или репозитории. Для интеграционных тестов используйте защищённые переменные окружения в CI и мокируйте внешние сервисы.

Краткая галерея пограничных случаев

  • Некорректные типы аргументов
  • Плавающие точки: .1 + .2
  • Переполнение при очень больших целых (редко в Python)
  • Настройки локали/кодировки при работе со строками

1‑строчный глоссарий

  • Fixture — подготовка/очистка тестовых данных
  • Parametrize — запуск теста с набором входов
  • ExceptionInfo — объект с информацией об исключении
  • CI — непрерывная интеграция

Короткое резюме

Pytest даёт удобный, масштабируемый и расширяемый набор инструментов для тестирования Python-кода. Начните с простых assert-тестов, используйте parametrization и fixtures для повторного использования и стабильности, интегрируйте тесты в CI и следуйте чеклистам для ролей в команде.

Важное: тесты — инвестиция. Чем раньше вы их добавите, тем меньше времени уйдёт на отладку в будущем.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство