Spec-Zone.ru › pytest

Рекомендации по интеграции

Установка пакета с помощью pip

Для разработки рекомендуем использовать venv для виртуальных окружений и pip для установки приложения и всех его зависимостей, а также самого пакета pytest. Это позволит изолировать ваш код и его зависимости от системной установки Python.

Создайте файл pyproject.toml в корне репозитория, как описано в Упаковка проектов Python. Первые строки должны выглядеть так:

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "PACKAGENAME"
version = "PACKAGEVERSION"

где PACKAGENAME и PACKAGEVERSION — название и версия вашего пакета соответственно.

Затем можно установить пакет в режиме «редактирования», выполнив команду из того же каталога:

pip install -e .

это позволит изменять исходный код (как тестов, так и приложения) и запускать тесты повторно в любое время.

Соглашения об обнаружении тестов Python

pytest реализует следующие стандартные правила обнаружения тестов:

  • Если аргументы не указаны, сбор начинается с testpaths (если задан) или из текущего каталога. Также можно передавать в командной строке любые сочетания каталогов, имён файлов или идентификаторов узлов.
  • Рекурсивно обходить каталоги, кроме тех, которые соответствуют norecursedirs.
  • В этих каталогах искать файлы test_*.py или *_test.py, импортируемые по их имени тестового пакета.
  • Из этих файлов собирать тестовые элементы:

    • функции или методы тестов с префиксом test, находящиеся вне класса.
    • функции или методы тестов с префиксом test, находящиеся в классах тестов с префиксом Test (без метода __init__). Также учитываются методы, декорированные с помощью @staticmethod и @classmethods.

Примеры настройки обнаружения тестов см. в разделе Изменение стандартного обнаружения тестов Python.

В модулях Python pytest также обнаруживает тесты с помощью стандартного способа наследования от unittest.TestCase.

Выбор структуры тестов

pytest поддерживает две распространённые структуры тестов:

Тесты вне кода приложения

Размещение тестов в отдельном каталоге вне кода приложения может быть полезно, если у вас много функциональных тестов или по другим причинам вы хотите отделить тесты от кода приложения (что часто бывает хорошей идеей):

pyproject.toml
src/
    mypkg/
        __init__.py
        app.py
        view.py
tests/
    test_app.py
    test_view.py
    ...

Это даёт следующие преимущества:

  • Тесты можно запускать для установленной версии после выполнения pip install ..
  • Тесты можно запускать для локальной копии с редактируемой установкой после выполнения pip install --editable ..

Для новых проектов рекомендуем использовать importlib режим импорта (подробное объяснение см. в разделе какой режим импорта выбрать). Для этого добавьте в файл конфигурации следующее:

# content of pytest.toml
[pytest]
addopts = ["--import-mode=importlib"]

В целом, но особенно при использовании режима импорта по умолчанию prepend, настоятельно рекомендуется использовать структуру src. В этом случае корневой пакет приложения располагается во вложенном каталоге корневого каталога, то есть src/mypkg/ вместо mypkg.

Такая структура позволяет избежать многих распространённых ошибок и даёт множество преимуществ, которые лучше описаны в этой превосходной публикации в блоге Ionel Cristian Mărieș.

Примечание

Если вы не используете редактируемую установку и используете описанную выше структуру src, для запуска тестов непосредственно для локальной копии необходимо расширить путь поиска модулей Python. Это можно сделать разово, задав переменную окружения PYTHONPATH:

PYTHONPATH=src pytest

или задать это на постоянной основе с помощью переменной конфигурации pythonpath, добавив в файл конфигурации следующее:

toml

[pytest]
pythonpath = ["src"]

ini

[pytest]
pythonpath = src

Примечание

Если вы не используете редактируемую установку и не используете структуру src (mypkg непосредственно в корневом каталоге), можно воспользоваться тем, что Python по умолчанию помещает текущий каталог в sys.path, чтобы импортировать пакет, а затем выполнить python -m pytest для запуска тестов непосредственно для локальной копии.

Подробнее о различиях между вызовами pytest и python -m pytest см. в разделе Вызов pytest и python -m pytest.

См. также

Структура src и плоская структура

В руководстве пользователя по упаковке Python обсуждаются компромиссы между структурой src и структурой flat.

Тесты как часть кода приложения

Размещение каталогов с тестами непосредственно в пакете приложения полезно, если тесты напрямую связаны с модулями приложения и вы хотите распространять их вместе с приложением:

pyproject.toml
[src/]mypkg/
    __init__.py
    app.py
    view.py
    tests/
        __init__.py
        test_app.py
        test_view.py
        ...

В такой структуре тесты удобно запускать с помощью параметра --pyargs:

pytest --pyargs mypkg

pytest обнаружит место установки mypkg и соберёт оттуда тесты.

Обратите внимание, что эта структура также совместима со структурой src, рассмотренной в предыдущем разделе.

Примечание

Для приложения можно использовать пакеты пространств имён (PEP420), но pytest всё равно будет обнаруживать имя тестового пакета по наличию файлов __init__.py. Если вы используете одну из двух рекомендованных выше структур файловой системы, но не добавляете файлы __init__.py в каталоги, всё должно работать. Однако для «встроенных тестов» потребуется использовать абсолютные импорты, чтобы обращаться к коду приложения.

Примечание

В режимах импорта prepend и append, если pytest при обходе файловой системы обнаруживает тестовый файл "a/b/test_module.py", он определяет имя импорта следующим образом:

  • определяет basedir: это первый каталог при движении «вверх» (к корню), не содержащий __init__.py. Например, если и a, и b содержат файл __init__.py, родительский каталог a станет basedir.
  • выполняет sys.path.insert(0, basedir), чтобы сделать тестовый модуль импортируемым по полному имени импорта.
  • import a.b.test_module, где путь определяется заменой разделителей пути / на символы «.». Это означает, что необходимо придерживаться соглашения, согласно которому имена каталогов и файлов напрямую соответствуют именам импорта.

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

С параметром --import-mode=importlib всё проще, потому что pytest не нужно изменять sys.path, поэтому поведение становится гораздо более предсказуемым.

Выбор режима импорта

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

Поскольку пакетов, по которым можно определить полное имя пакета, нет, pytest импортирует ваши тестовые файлы как модули верхнего уровня. Тестовые файлы из первого примера (структура src) будут импортированы как модули верхнего уровня test_app и test_view путём добавления tests/ в sys.path.

По сравнению с режимом импорта importlib это имеет один недостаток: имена тестовых файлов должны быть уникальными.

Если вам нужны тестовые модули с одинаковыми именами, можно обойти это ограничение, добавив файлы __init__.py в каталог tests и его подкаталоги, превратив их в пакеты:

pyproject.toml
mypkg/
    ...
tests/
    __init__.py
    foo/
        __init__.py
        test_view.py
    bar/
        __init__.py
        test_view.py

Теперь pytest будет загружать модули как tests.foo.test_view и tests.bar.test_view, что позволит использовать модули с одинаковыми именами. Однако это создаёт более тонкую проблему: чтобы загрузить тестовые модули из каталога tests, pytest добавляет корень репозитория в начало sys.path, что также приводит к тому, что становится доступен для импорта и mypkg.

Это создаёт проблему, если вы используете такой инструмент, как tox, для тестирования пакета в виртуальном окружении, поскольку вам нужно тестировать установленную версию пакета, а не локальный код из репозитория.

У режима импорта importlib нет перечисленных выше недостатков, поскольку при импорте тестовых модулей sys.path не изменяется.

tox

Когда работа завершена и нужно убедиться, что ваш пакет проходит все тесты, стоит обратить внимание на tox — инструмент автоматизации тестирования в virtualenv. tox помогает настроить окружения virtualenv с предварительно заданными зависимостями, а затем выполнить предварительно настроенную команду тестирования с параметрами. Тесты будут запускаться для установленного пакета, а не для его исходного кода в рабочей копии, что помогает обнаружить проблемы с упаковкой.

Не запускайте через setuptools

Интеграция с setuptools не рекомендуется: не следует использовать python setup.py test или pytest-runner, и в будущем они могут перестать работать.

Этот способ объявлен устаревшим, поскольку зависит от устаревших функций setuptools и опирается на функции, нарушающие механизмы безопасности pip. Например, «setup_requires» и «tests_require» обходят pip --require-hashes. Дополнительную информацию и инструкции по миграции см. в уведомлении pytest-runner. См. также pypa/setuptools#1684.

setuptools намерен удалить команду test.

Проверка с помощью flake8-pytest-style

Чтобы убедиться, что pytest правильно используется в вашем проекте, может быть полезно воспользоваться плагином flake8 flake8-pytest-style.

flake8-pytest-style выявляет распространённые ошибки и нарушения стиля кода в тестах pytest, например неправильное использование фикстур, имён тестовых функций и маркеров. С помощью этого плагина можно обнаружить такие ошибки на ранних этапах разработки и обеспечить единообразие и удобство сопровождения тестового кода pytest.

Список проверок, выполняемых flake8-pytest-style, можно найти на его странице PyPI.

Примечание

flake8-pytest-style не является официальным проектом pytest. Некоторые правила требуют соблюдать определённые стилистические предпочтения, например использовать @pytest.fixture() вместо @pytest.fixture, однако плагин можно настроить в соответствии с предпочтительным стилем.

Использование строгого режима pytest

Добавлено в версии 9.0.

В pytest есть набор параметров конфигурации, которые делают его работу более строгой. По умолчанию эти параметры отключены для обеспечения совместимости или по другим причинам, но, если возможно, их следует включить.

Все параметры строгости можно включить одновременно, задав параметр конфигурации strict:

toml

[pytest]
strict = true

ini

[pytest]
strict = true

Описание параметров, включаемых этим параметром, и их воздействия см. в документации strict.

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

toml

[pytest]
strict_config = true
strict_markers = true
strict_parametrization_ids = true
strict_xfail = true

ini

[pytest]
strict_config = true
strict_markers = true
strict_parametrization_ids = true
strict_xfail = true

Если вы хотите использовать строгий режим, но столкнулись с проблемой, связанной с определённым параметром, его можно отключить отдельно:

toml

[pytest]
strict = true
strict_parametrization_ids = false

ini

[pytest]
strict = true
strict_parametrization_ids = false

© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/explanation/goodpractices.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API