Pytest
Pytest — фреймворк для тестирования на языке программирования Python, изначально созданный в рамках проекта PyPy и в настоящее время разрабатываемый сообществом добровольцев[1]. Предназначен для написания различных видов тестов, включая модульные тесты, интеграционные тесты, сквозные тесты и функциональные тесты. Среди основных возможностей: параметризованное тестирование, использование фикстур, а также переписывание assert-выражений для подробного вывода причин неудачных тестов. Последняя версия 8.4.2 (3 сентября 2025 года)[2] требует Python 3.9 или новее[2][3].
Фикстуры Pytest предоставляют контексты для тестов посредством передачи имён параметров в тестовые функции; параметризация позволяет избежать дублирования кода при проверке нескольких наборов входных и выходных данных; переписанные выражения assert обеспечивают расширенный вывод при ошибках.
Общие сведения
| Pytest | |||
|---|---|---|---|
| Тип | фреймворк для тестирования программного обеспечения | ||
| Авторы | Krekel и др. | ||
| Разработчик | сообщество pytest-dev | ||
| Написана на | Python | ||
| Интерфейс | командная строка | ||
| Операционные системы | Windows, macOS, Linux | ||
| Языки интерфейса | английский | ||
| Первый выпуск | ноябрь 2010 | ||
| Аппаратные платформы | macOS, Windows, POSIX | ||
| Последняя версия | 8.4.2 (3 сентября 2025) | ||
| Репозиторий | github.com/pytest-dev/py… | ||
| |||
| |||
| Состояние | активное | ||
| Лицензия | MIT License | ||
| Сайт | pytest.org | ||
История
Pytest был разработан как третьесторонний пакет для устранения недостатков встроенного в Python модуля unittest[4]. Он возник в рамках альтернативной реализации Python — PyPy. С момента создания PyPy в начале 2003 года проект уделял большое внимание тестированию, включая модульные тесты для нового кода, регрессионные тесты и интеграционное тестирование с использованием тестов из стандартной поставки CPython[4].
В середине 2004 года в рамках PyPy появился фреймворк utest, на который участники проекта начали переносить существующие тесты. В то же время на EuroPython 2004 был разработан модуль std, заложивший такие принципы, как переписывание assert. В конце 2004 года проект std был переименован в py, std.utest стал называться py.test, а сама библиотека py была выделена из PyPy[5]. 4 августа 2009 года состоялся выпуск версии py 1.0.0, которая представила такие фундаментальные возможности, как фикстуры (на тот момент funcargs) и плагинную архитектуру[5]. В ноябре 2010 года был выпущен pytest 2.0.0 как отдельный пакет, не зависящий от py. Название py.test сохранялось до августа 2016 года, когда после выпуска pytest 3.0.0 стандартной точкой входа командной строки стал pytest[5].
В последующие годы вышли несколько мажорных версий: 4.0 (13 ноября 2018 года)[6], 5.0 (28 июня 2019 года)[6], 6.0 (28 июля 2020 года)[7], 7.0 (4 февраля 2022 года)[7] и 8.0 (27 января 2024 года)[8]. Проект продолжает активно развиваться[9]. По состоянию на сентябрь 2025 года последней стабильной версией является 8.4.2, выпущенная 3 сентября 2025 года.
Платформа для обеспечения безопасности разработчиков Snyk считает Pytest одним из ключевых проектов экосистемы Python благодаря его популярности. Некоторые известные проекты, такие как Mozilla и Dropbox, перешли с unittest и nose (другого пакета для тестирования) на использование pytest[10][11].[12][13]
Архитектура
Функциональность Pytest обеспечивается не монолитным движком, а совокупностью нескольких ключевых компонентов, которые вместе образуют ядро фреймворка[14].
- Механизм обнаружения тестов (Test Discovery). При запуске Pytest автоматически сканирует каталоги и файлы в поиске тестов, следуя правилам именования: файлы должны называться `test_*.py` или `*_test.py`, а тестовые функции и методы — начинаться с префикса `test_`[15].
- Исполнитель тестов (Test Runner). После обнаружения тестов Pytest последовательно выполняет их. Команда `pytest` в терминале запускает все найденные тесты, но также позволяет указать конкретный файл или отдельную функцию для запуска[16][17].
- Архитектура на основе плагинов. Одной из главных особенностей Pytest является его расширяемая архитектура, которая позволяет изменять или дополнять практически все компоненты с помощью плагинов. Это даёт возможность добавлять новые функции и интегрироваться с другими системами[18].
- Фикстуры (Fixtures). Функции, которые Pytest запускает до и после выполнения тестов для подготовки тестового окружения (например, подключения к базе данных) и его последующей очистки[19].
- Переопределение `assert`. Pytest использует стандартный оператор `assert` языка Python, но перехватывает его для предоставления подробных отчётов об ошибках. В случае сбоя фреймворк анализирует выражение и показывает значения переменных, которые привели к ошибке, что упрощает отладку[18][14].
Pytest взаимодействует с файлами двух основных типов: читаемые файлы, используемые для тестов и конфигурации, и создаваемые файлы, содержащие отчёты о результатах.
- Файлы с тестами: Pytest автоматически обнаруживает и выполняет тесты из файлов Python (с расширением `.py`)[20]. Для этого имена файлов должны соответствовать шаблонам `test_*.py` или `*_test.py`[20]. Внутри этих файлов фреймворк ищет функции, имена которых начинаются с префикса `test_`, и классы с префиксом `Test`[21].
- Конфигурационные файлы: Для настройки поведения Pytest ищет параметры в нескольких файлах в порядке убывания приоритета[22]:
- `pytest.ini` — наиболее распространённый файл конфигурации.
- `pyproject.toml` — настройки указываются в секции `[tool.pytest.ini_options]`.
- `tox.ini` — используется инструментом `tox`, может содержать секцию `[pytest]`.
- `setup.cfg` — файл `setuptools`, настройки размещаются в секции `[tool:pytest]`.
Pytest предоставляет гибкие возможности для создания отчётов о результатах тестирования, как встроенные, так и с помощью плагинов[23].
- Текстовый отчёт в консоли: Стандартный способ вывода, который предоставляет краткую сводку о пройденных, проваленных и пропущенных тестах[24]. Детализацию можно настраивать с помощью опций командной строки, например, отключая трассировку стека (`--tb=no`)[25].
- JUnit-XML: Встроенная возможность для создания отчётов в формате JUnit XML, который широко используется системами непрерывной интеграции (CI/CD), такими как Jenkins или GitLab[26]. Отчёт генерируется с помощью флага `--junitxml=<путь к файлу>.xml`[27].
- HTML: Для создания наглядных отчётов в формате HTML используется популярный плагин `pytest-html`[28]. Он генерирует единый файл, который удобно просматривать в браузере, с помощью команды `pytest --html=report.html`[29][30].
- JSON: Для программной обработки результатов тестирования используется формат JSON. Плагин `pytest-json-report` позволяет создавать отчёты с детальной структурированной информацией о тестах, их статусах и логах[31]. Отчёт генерируется командой `pytest --json-report`[32].
Возможности
Часто при тестировании программ нужно проверять функцию на различных входных значениях. Для полноценной проверки функциональности, как правило, требуется многократное тестирование с разными наборами данных, и если писать такие тесты отдельно, неизбежно дублирование кода, поскольку действия идентичны и различаются только значениями. Параметризация в Pytest позволяет объединить различные варианты входных данных и результата в один тест, который проходит по всем комбинациям и отдельно выводит результат для каждого набора[33].
Параметризованные тесты в pytest помечаются декоратором @pytest.mark.parametrize(argnames, argvalues), где argnames — строка с именами параметров, разделённых запятыми, а argvalues — список значений, которые будут подставляться. Для нескольких имён в argnames argvalues выступает в роли списка кортежей значений в том же порядке, что перечислены имена. При запуске каждый набор данных отрабатывается как отдельный тест с уникальным идентификатором, который можно использовать для выборочного запуска[34].[33]:52–58
Выражение assert является одним из важных средств информирования о провале теста, сравнивая ожидаемое со значением, полученным в результате выполнения кода[33].[33]:32–34 Обычный assert в Python вызывает исключение AssertionError без подробностей при неудаче, а в Pytest механизм assert переписывается для вывода расширенной информации, в частности, подробностей о сравнении выражений. Для сравнения, в unittest используются более громоздкие конструкции:
| Pytest | unittest |
|---|---|
assert x
|
assertTrue(x)
|
assert x == y
|
assertEqual(x, y)
|
assert x <= y
|
assertLessEqual(x, y)
|
Такой дополнительный синтаксис unittest обусловлен его наследованием от JUnit для Java, в то время как Pytest перехватывает и расширяет стандартные assert Python, делая тесты лаконичнее[33][12].
Тесты Pytest проверяют корректность выполнения программного кода[35] по шаблону AAA (Arrange, Act, Assert)[36][35].
Фикстуры Pytest создают контекст тестирования: они позволяют подготовить состояние среды или передать нужные данные в тестовую функцию. По сути, фикстуры реализуют стадию arrange в тестах типа AAA[36][35]. Фикстуры Pytest могут выполняться до старта тестов (setup) или после (для очистки), однако отличаются от setup/teardown в unittest и nose. Функции-фикстуры помечаются декоратором @pytest.fixture, после чего их имена можно использовать как параметры тестовых функций[37]. Если имя фикстуры указано в параметрах теста, Pytest сначала ищет такую фикстуру в текущем модуле, а если не находит — ищет в файле conftest.py[33][33]:61
Пример:
import pytest
@pytest.fixture
def dataset():
"""Возвращает тестовые данные"""
return {'data1': 1, 'data2': 2}
def test_dataset(dataset):
"""Проверка значения фикстуры"""
assert dataset == {'data1': 1, 'data2': 2}
В приведённом примере фикстура dataset возвращает словарь, который затем передаётся тестовой функции test_dataset для проверки. Помимо размещения фикстур в тестовом модуле, их можно выносить в файл conftest.py в каталоге tests. При наличии нескольких каталогов tests допускается множество файлов conftest.py для разных подмножеств тестов[33][33]:63
В Pytest область действия (scope) фикстуры позволяет управлять тем, когда она будет вызываться. Существует четыре значения области: функция (function), класс (class), модуль (module) и сессия (session). По умолчанию область действия фикстуры в pytest — функция, то есть фикстура используется для каждой тестовой функции по отдельности. Использование более широкой области действия позволяет ускорить тестирование за счёт уменьшения числа вызовов фикстуры. Фикстуры с областью class вызываются один раз на класс тестов, а по аналогии с остальными типами. Для смены области действия нужно добавить параметр scope к декоратору фикстуры, например, @pytest.fixture(scope="class").[33][33]:72[38]..
Pytest позволяет фильтровать тесты — запускать только нужные или изменять их поведение по выборам пользователя. С помощью опции -k (например, pytest -k some_name) можно запускать только те тесты, в имени которых содержится some_name. Также работает противоположное условие — pytest -k "not some_name" запускает тесты, не содержащие some_name[39].
Также для фильтрации используются маркеры Pytest — это декораторы Python с синтаксисом @pytest.mark.<markername>, размещаемые над тестовой функцией. Провести запуск только тестов с определённым маркером можно через pytest -m <markername>. Список всех существующих маркеров (в том числе пользовательских, зарегистрированных в pytest.ini) можно получить с помощью pytest --markers[33].[33]:13, 147
Характеристики
Pytest является кроссплатформенным фреймворком и работает на большинстве операционных систем, где установлен Python совместимой версии[40]. Основные поддерживаемые платформы включают Windows, macOS[41] и различные дистрибутивы Linux[42].
Интерфейс командной строки Pytest и весь стандартный вывод, включая результаты тестов, сообщения об ошибках и справочную информацию, представлены только на английском языке[43]. Встроенные механизмы для локализации интерфейса отсутствуют[44]. Существующие плагины, связанные с переводами, например `pytest-translations`, предназначены для тестирования файлов локализации пользовательских приложений (форматов `.po` и `.mo`), а не для перевода интерфейса самого фреймворка[45].
Pytest является инструментом с интерфейсом командной строки (CLI)[46]. Основное взаимодействие с фреймворком, включая запуск тестов и настройку параметров, происходит через текстовые команды в терминале или консоли. Тесты запускаются командой `pytest`, которая может принимать различные флаги для управления процессом, например, для выбора конкретных тестов или изменения детализации отчёта[47]. Фреймворк также можно вызвать как модуль Python с помощью команды `python -m pytest`[48].
Несмотря на то, что Pytest не имеет встроенного графического интерфейса (GUI), его можно использовать в графической среде несколькими способами[46]:
- Интеграция со средами разработки (IDE). Многие популярные IDE, такие как PyCharm и Visual Studio Code, имеют встроенную поддержку Pytest. Они предоставляют графический интерфейс для запуска тестов, просмотра результатов и отладки, но для выполнения тестов «под капотом» используют CLI фреймворка.
- Сторонние инструменты и плагины. Существуют отдельные проекты, предоставляющие графический или веб-интерфейс для Pytest. Например, плагин `pytest-commander` создаёт интерактивный интерфейс для запуска тестов с отображением результатов в веб-браузере[49]. Другие проекты, такие как `pytest-gui`, предлагают полноценный GUI, а `pytesttui` — текстовый пользовательский интерфейс (TUI)[50].
Разработка и сообщество
Pytest является проектом с открытым исходным кодом, который разрабатывается и поддерживается сообществом добровольцев. Координацией разработки ядра фреймворка, сопутствующего кода и плагинов занимается группа pytest-dev на платформе GitHub, объединяющая всех участников проекта. Любой желающий может принять участие в развитии фреймворка, сообщая об ошибках, предлагая улучшения или работая над кодом и документацией.
Хотя вклад вносит большое количество людей, ключевые решения принимает и осуществляет поддержку основная команда (core team). В неё входят[51]:
Применение в проектах
Pytest используется во многих крупных проектах. Например, Mozilla и Dropbox перешли на его использование со стандартного модуля `unittest` и фреймворка `nose`[52][53]. Фреймворк также нашёл широкое применение в российских технологических компаниях, которые строят на его основе собственные тестовые инфраструктуры.
Компания Ozon использует Pytest для автоматизации тестирования в микросервисной архитектуре. На его базе созданы решения для тестирования API, а также для автоматической генерации тестовых клиентов для gRPC и REST-сервисов на основе их спецификаций. Для формирования отчётов применяется интеграция с Allure[54].
В Яндексе был разработан и открыт для сообщества фреймворк `testsuite`, построенный на основе Pytest. Он предназначен для функционального тестирования сервисов по принципу «чёрного ящика» и расширяет стандартные возможности Pytest инструментами для управления тестовым окружением (автоматический запуск баз данных, таких как PostgreSQL, MongoDB и Redis), встроенным мок-сервером и фикстурами для прямого доступа к данным[55].
Общие тенденции использования Pytest в индустрии отражаются в докладах на профильных конференциях. Среди обсуждаемых тем — применение фреймворка для валидации контрактов API с помощью JSON Schema, а также его использование в финтех-проектах для тестирования бэкенда с большим количеством микросервисов. Сложность таких систем приводит к появлению в командах выделенных ролей, например SDET (Software Development Engineer in Test), ответственных за поддержку и развитие тестовой инфраструктуры[56].