Фреймворк pytest
может обрабатывать особым образом тестовые функции, которые, например, не могут быть запущены на определенных платформах и при этом представлять тестовую сводку, сохраняя зеленый набор тестов.
Декоратор pytest.mark.skip()
означает, что тест ожидаемо пройдет только при соблюдении некоторых условий, в противном случае pytest
должен вообще пропустить выполнение теста. Типичными примерами являются пропуск тестов только для Windows на платформах, отличных от Windows, или пропуск тестов, зависящих от внешнего ресурса, который в данный момент недоступен (например, базы данных).
Чтобы не загромождать вывод, подробная информация о пропущенных тестах по умолчанию не отображается. Чтобы увидеть детали, можно использовать опцию -r с "коротким" буквам, отображаемым в ходе теста, например, запуск: $ pytest -rs
- означает, что нужно показать дополнительную информацию о skipped
тестах.
@pytest.mark.skip()
;pytest.skip()
;@pytest.mark.skipif()
;@pytest.importorskip()
;skip
и skipif
в параметрах к тесту.Безоговорочно пропускать все тесты в модуле:
pytestmark = pytest.mark.skip("пропускаем все тесты в модуле")
Пропустить все тесты в модуле на основе некоторого условия:
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="тесты только для linux")
Пропустить все тесты в модуле, если, например, нельзя импортировать модуль qrcode
:
pexpect = pytest.importorskip("qrcode")
@pytest.mark.skip()
.Декоратор/маркер @pytest.mark.skip(reason=None)
безоговорочно пропускает тестовую функцию.
Самый простой способ пропустить тестовую функцию - это применить к ней декоратор @pytest.mark.skip
, которому можно передать необязательную причину reason
:
@pytest.mark.skip(reason="в настоящее время нет" "возможности протестировать") def test_the_unknown(): ...
pytest.skip()
.Функция skip(reason[, allow_module_level=False, msg=None])
пропускает выполнение теста с данным сообщением reason
.
Эту функцию следует вызывать только во время тестирования (установка, вызов или демонтаж) или во время сбора тестов с использованием флага allow_module_level
. Эту функцию можно вызывать и в doctests
.
Принимаемые аргументы:
reason
: (str
) - сообщение, показывающее причину пропуска.allow_module_level=False
: (bool
) - позволяет вызывать эту функцию на уровне модуля, пропуская остальную часть модуля.msg
: (str
) - то же, что и reason
, но устарело. Будет удалено в будущих версиях.В качестве альтернативы, вызвав функцию pytest.skip(reason)
можно принудительно пропустить тест во время выполнения или отладки:
def test_function(): if not valid_config(): pytest.skip("неподдерживаемая конфигурация")
Когда невозможно оценить условие пропуска во время импорта, полезен императивный метод.
Также можно пропустить весь модуль, применив функцию pytest.skip(reason, allow_module_level=True)
на уровне модуля:
import sys import pytest if not sys.platform.startswith("win"): pytest.skip("пропуск тестов только для Windows", allow_module_level=True)
Примечание. Если нужно, чтобы тест будет пропущен при определенных условиях, таких как несоответствие платформ или зависимостей, то предпочтительнее явное объявление декоратора
@pytest.mark.skip
.
@pytest.mark.skipif()
.Декоратор/маркер @pytest.mark.skipif(condition, *, reason=None)
пропускает тестовую функцию, если условие condition
истинно.
Принимаемые аргументы.
condition
: выражение, которое возвращает True
/False
или условие в виде строки, которая будет обрабатываться функцией eval()
.
Например:
@pytest.mark.skipif("not config.getvalue('db')") def test_function(): pass
Во время настройки тестовой функции строка с условием оценивается вызовом eval("not config.getvalue('db')", namespace)
. Пространство имен namespace
содержит все глобальные переменные модуля и как минимум os
и sys
.
Эквивалентом "логического условия” является:
@pytest.mark.skipif(not pytest.config.getvalue("db"), reason="--db was not specified") def test_function(): pass
reason=None
: (str
) - причина, по которой пропускается тестовая функция.
Если необходимо пропустить что-то условно, то можно использовать декоратор @pytest.mark.skipif()
. Пример пропуска теста при запуске в интерпретаторе, предшествующем Python3.10:
import sys @pytest.mark.skipif(sys.version_info < (3, 10), reason="требуется python3.10 или выше") def test_function(): ...
Если во время сбора тестов условие оценивается как True
, то тестовая функция будет пропущена, а указанная причина появится в сводке при использовании опций $ pytest -rs
.
Можно совместно использовать вызов pytest.mark.skipif()
между модулями:
# test_mymodule.py import mymodule minversion = pytest.mark.skipif( mymodule.__versioninfo__ < (1, 1), reason="требуется как минимум mymodule-1.1" ) @minversion def test_function(): ...
Можно импортировать маркер и повторно использовать его в другом тестовом модуле:
# test_myothermodule.py from test_mymodule import minversion @minversion def test_anotherfunction(): ...
Для больших наборов тестов обычно рекомендуется иметь один файл, в котором определены маркеры, которые затем последовательно применяются в наборе тестов.
Можно использовать декоратор @pytest.mark.skipif()
(как и любой другой маркер) для классов:
@pytest.mark.skipif(sys.platform == "win32", reason="не запускается в Windows") class TestPosixCalls: def test_function(self): """не будет настроен или запущен под платформой win32""" ... ...
Если условие sys.platform == "win32"
истинно, то этот маркер выдаст результат пропуска для каждого из тестовых методов этого класса.
Если необходимо, то можно пропустить все тестовые функции модуля, для этого нужно использовать глобальную метку pytestmark
:
# test_module.py pytestmark = pytest.mark.skipif(...)
Если к тестовой функции применено несколько декораторов @pytest.mark.skipif()
, то она будет пропущена, если какое-либо из условий этих декораторов имеет значение True
.
Иногда может потребоваться пропустить несколько файлов или каталог с тестами, например, если тесты основаны на функциях, специфичных для версии Python, или содержат код, который не надо запускать в pytest
. В этом случае необходимо исключить эти файлы и каталоги во время сбора тестов при запуске. Дополнительные сведения смотрите раздел "Настройка собственного набора тестов" в материале "Как запускать/вызывать тесты pytest в Python".
pytest.importorskip()
.Функция pytest.importorskip(modname, minversion=None, reason=None)
импортирует и возвращает запрошенный модуль modname
или пропускает текущий тест, если модуль не может быть импортирован.
Принимаемые аргументы:
modname
: (str
) - имя модуля для импорта.minversion
(str
) - если указано, то это атрибут __version__
импортированного модуля, должен быть не ниже указанной минимальной версии, иначе тест все равно будет пропущен.reason
: (str
) - если указана, то это причина, когда модуль не может быть импортирован. Отображается в виде сообщения.Можно пропустить тесты для отсутствующего импорта, используя функцию pytest.importorskip()
на уровне модуля, в тесте или в функции настройки теста.
docutils = pytest.importorskip("docutils")
Код выше означает, что если нельзя импортировать docutils
, то это приведет к пропуску результата теста. Также можно пропустить результат теста в зависимости от номера версии библиотеки:
docutils = pytest.importorskip("docutils", minversion="0.3")
Версия будет считана из атрибута __version__
указанного модуля.
skip
и skipif
в параметрах к тесту.Можно применять маркеры, такие как pytest.mark.skip()
и pytest.mark.skipif()
к отдельным экземплярам теста при использовании передаваемых к нему параметров:
import sys import pytest @pytest.mark.parametrize( ("n", "expected"), [ (1, 2), pytest.param( 0, 1, marks=pytest.mark.skip(reason="даст сбой") ), (2, 3), (3, 4), (4, 5), pytest.param( 10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k") ), ], ) def test_increment(n, expected): assert n + 1 == expected