Изменение стандартного обнаружения тестов (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