Spec-Zone.ru › pytest

Изменение стандартного обнаружения тестов (Python)

Игнорирование путей при сборе тестов

Вы можете легко игнорировать определённые каталоги и модули с тестами при сборе, передав параметр --ignore=path в командной строке. pytest позволяет указать несколько параметров --ignore. Пример:

tests/
|-- example
|   |-- test_example_01.py
|   |-- test_example_02.py
|   '-- test_example_03.py
|-- foobar
|   |-- test_foobar_01.py
|   |-- test_foobar_02.py
|   '-- test_foobar_03.py
'-- hello
    '-- world
        |-- test_world_01.py
        |-- test_world_02.py
        '-- test_world_03.py

Теперь, если вызвать pytest с --ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/, вы увидите, что pytest собирает только тестовые модули, не соответствующие указанным шаблонам:

=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 5 items

tests/example/test_example_01.py .                                   [ 20%]
tests/example/test_example_02.py .                                   [ 40%]
tests/example/test_example_03.py .                                   [ 60%]
tests/foobar/test_foobar_01.py .                                     [ 80%]
tests/foobar/test_foobar_02.py .                                     [100%]

========================= 5 passed in 0.02 seconds =========================

Параметр --ignore-glob позволяет игнорировать пути к файлам с тестами на основе подстановочных символов в стиле оболочки Unix. Чтобы исключить тестовые модули, имена которых заканчиваются на _01.py, выполните pytest с параметром --ignore-glob='*_01.py'.

Исключение тестов при сборе

Отдельные тесты можно исключить при сборе, передав параметр --deselect=item. Например, предположим, что tests/foobar/test_foobar_01.py содержит test_a и test_b. Можно запустить все тесты из tests/, кроме tests/foobar/test_foobar_01.py::test_a, вызвав pytest с --deselect=tests/foobar/test_foobar_01.py::test_a. pytest позволяет указать несколько параметров --deselect.

Сохранение дублирующихся путей, указанных в командной строке

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

pytest path_a path_a

...
collected 1 item
...

Тесты собираются только один раз.

Чтобы собрать дублирующиеся тесты, используйте параметр --keep-duplicates в командной строке. Пример:

pytest --keep-duplicates path_a path_a

...
collected 2 items
...

Изменение рекурсивного обхода каталогов

Вы можете задать параметр norecursedirs в файле конфигурации:

# content of pytest.toml
[pytest]
norecursedirs = [".svn", "_build", "tmp*"]

Это укажет pytest не выполнять рекурсивный обход типичных каталогов subversion или sphinx-build, а также любых каталогов с префиксом tmp.

Изменение соглашений об именовании

Вы можете настроить другие соглашения об именовании, задав параметры python_files, python_classes и python_functions в файле конфигурации. Вот пример:

# content of pytest.toml
# Example 1: have pytest look for "check" instead of "test"
[pytest]
python_files = ["check_*.py"]
python_classes = ["Check"]
python_functions = ["*_check"]

В этом случае pytest будет искать тесты в файлах, соответствующих шаблону glob check_* .py, в классах с префиксом Check, а также в функциях и методах, соответствующих шаблону *_check. Например, если у нас есть:

# content of check_myapp.py
class CheckMyApp:
    def simple_check(self):
        pass

    def complex_check(self):
        pass

Сбор тестов будет выглядеть так:

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 2 items

<Dir pythoncollection.rst-216>
  <Module check_myapp.py>
    <Class CheckMyApp>
      <Function simple_check>
      <Function complex_check>

======================== 2 tests collected in 0.12s ========================

Можно указать несколько шаблонов glob, разделив их пробелом:

# content of pytest.toml
# Example 2: have pytest look for files with "test" and "example"
[pytest]
python_files = ["test_*.py", "example_*.py"]

Примечание

параметры python_functions и python_classes не влияют на обнаружение тестов unittest.TestCase, поскольку pytest делегирует обнаружение методов тестовых случаев коду unittest.

Интерпретация аргументов командной строки как пакетов Python

Вы можете использовать параметр --pyargs, чтобы pytest пытался интерпретировать аргументы как имена пакетов Python, определять соответствующие пути в файловой системе, а затем запускать тест. Например, если у вас установлен unittest2, можно ввести:

pytest --pyargs unittest2.test.test_skipping -q

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

# content of pytest.toml
[pytest]
addopts = ["--pyargs"]

Теперь при простом вызове pytest NAME будет проверяться, существует ли NAME как импортируемый пакет/модуль; в противном случае он будет рассматриваться как путь в файловой системе.

Просмотр собранных тестов

Вы всегда можете просмотреть дерево сбора, не запуская тесты:

. $ pytest --collect-only pythoncollection.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 3 items

<Dir pythoncollection.rst-216>
  <Dir CWD>
    <Module pythoncollection.py>
      <Function test_function>
      <Class TestClass>
        <Function test_method>
        <Function test_anothermethod>

======================== 3 tests collected in 0.12s ========================

Настройка сбора тестов

Можно легко указать pytest искать тесты во всех файлах Python:

# content of pytest.toml
[pytest]
python_files = ["*.py"]

Однако во многих проектах есть setup.py, который не нужно импортировать. Кроме того, некоторые файлы могут быть импортируемы только определённой версией Python. В таких случаях можно динамически задать файлы, которые нужно игнорировать, перечислив их в файле conftest.py:

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore.append("pkg/module_py2.py")

а затем создать файл модуля, например такой:

# content of pkg/module_py2.py
def test_only_on_python2():
    try:
        assert 0
    except Exception, e:
        pass

и пустой файл setup.py, например такой:

# content of setup.py
0 / 0  # will raise exception if imported

При запуске с интерпретатором Python 2 будет найден один тест, а файл setup.py будет пропущен:

#$ pytest --collect-only
====== test session starts ======
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
<Module 'pkg/module_py2.py'>
  <Function 'test_only_on_python2'>

====== 1 tests found in 0.04 seconds ======

При запуске с интерпретатором Python 3 будут пропущены и единственный тест, и файл setup.py:

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 0 items

======================= no tests collected in 0.12s ========================

Также можно игнорировать файлы на основе подстановочных символов в стиле оболочки Unix, добавив шаблоны в collect_ignore_glob.

В следующем примере conftest.py игнорирует файл setup.py, а также все файлы, заканчивающиеся на *_py2.py, при запуске с интерпретатором Python 3:

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore_glob = ["*_py2.py"]

Начиная с Pytest 2.6, пользователи могут запретить pytest обнаруживать классы, начинающиеся с Test, задав логический атрибут __test__ со значением False.

# Will not be discovered as a test
class TestClass:
    __test__ = False

Примечание

Если вы работаете с абстрактными тестовыми классами и хотите избежать ручной установки атрибута __test__ для подклассов, можно использовать класс-миксин, который сделает это автоматически. Например:

# Mixin to handle abstract test classes
class NotATest:
    def __init_subclass__(cls):
        cls.__test__ = NotATest not in cls.__bases__


# Abstract test class
class AbstractTest(NotATest):
    pass


# Subclass that will be collected as a test
class RealTest(AbstractTest):
    def test_example(self):
        assert 1 + 1 == 2

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

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

Spec-Zone.ru

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