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

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
Автор
Редакция

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

Как устроить идеальную вечеринку для просмотра ТВ
Развлечения

Как устроить идеальную вечеринку для просмотра ТВ

Как распаковать несколько RAR‑файлов сразу
Инструменты

Как распаковать несколько RAR‑файлов сразу

Приватный просмотр в Linux: как и зачем
Приватность

Приватный просмотр в Linux: как и зачем

Windows 11 не видит iPod — способы исправить
Руководство

Windows 11 не видит iPod — способы исправить

PS5: как настроить игровые пресеты
Консоли

PS5: как настроить игровые пресеты

Как переключить камеру в Omegle на iPhone и Android
Руководство

Как переключить камеру в Omegle на iPhone и Android