Spec-Zone.ru › pytest

Как запускать doctests

По умолчанию все файлы, соответствующие шаблону test*.txt, проверяются с помощью стандартного модуля Python doctest. Изменить шаблон можно с помощью команды:

pytest --doctest-glob="*.rst"

в командной строке. Параметр --doctest-glob можно указать в командной строке несколько раз.

Если у вас есть текстовый файл, например такой:

# content of test_example.txt

hello this is a doctest
>>> x = 3
>>> x
3

то можно просто запустить pytest напрямую:

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 1 item

test_example.txt .                                                   [100%]

============================ 1 passed in 0.12s =============================

По умолчанию pytest будет собирать файлы test*.txt в поисках директив doctest, но вы можете указать дополнительные шаблоны с помощью параметра --doctest-glob (можно указать несколько).

Помимо текстовых файлов, можно также запускать doctests непосредственно из docstring классов и функций, в том числе из тестовых модулей, используя параметр --doctest-modules:

# content of mymodule.py
def something():
    """a doctest in a docstring
    >>> something()
    42
    """
    return 42
$ pytest --doctest-modules
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items

mymodule.py .                                                        [ 50%]
test_example.txt .                                                   [100%]

============================ 2 passed in 0.12s =============================

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

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

Кодировка

По умолчанию используется кодировка UTF-8, но для файлов doctest можно указать другую кодировку с помощью параметра конфигурации doctest_encoding:

toml

[pytest]
doctest_encoding = "latin1"

ini

[pytest]
doctest_encoding = latin1

Использование параметров ‘doctest’

Стандартный модуль Python doctest предоставляет несколько параметров для настройки строгости тестов doctest. В pytest эти флаги можно включить с помощью файла конфигурации.

Например, чтобы pytest игнорировал завершающие пробелы и длинные трассировки стека исключений, достаточно написать:

toml

[pytest]
doctest_optionflags = ["NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL"]

ini

[pytest]
doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL

Кроме того, параметры можно включить с помощью встроенного комментария в самом тесте doctest:

>>> something_that_raises()  # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
ValueError: ...

В pytest также добавлены новые параметры:

  • ALLOW_UNICODE: если включён, префикс u удаляется из строк Unicode в ожидаемом выводе doctest. Это позволяет запускать doctests без изменений в Python 2 и Python 3.
  • ALLOW_BYTES: аналогично, префикс b удаляется из байтовых строк в ожидаемом выводе doctest.
  • NUMBER: если включён, числа с плавающей точкой должны совпадать лишь с точностью, указанной в ожидаемом выводе doctest. Числа сравниваются с помощью pytest.approx() с относительной погрешностью, равной этой точности. Например, при сравнении 3.14 с pytest.approx(math.pi, rel=10**-2) следующий вывод должен совпадать только до 2 знаков после запятой:

    >>> math.pi
    3.14
    

    Если указать 3.1416, фактический вывод должен будет совпадать примерно до 4 знаков после запятой и так далее.

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

    Expected:
        0.233
    Got:
        0.23300000000000001
    

    Параметр NUMBER также поддерживает списки чисел с плавающей точкой — на самом деле он сопоставляет числа с плавающей точкой в любом месте вывода, даже внутри строки! Поэтому включать его глобально в doctest_optionflags в файле конфигурации может быть неуместно.

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

Продолжение после сбоя

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

pytest --doctest-modules --doctest-continue-on-failure

Формат вывода

Формат вывода различий при сбое doctests можно изменить, используя один из стандартных параметров форматирования модуля doctest (см. doctest.REPORT_UDIFF, doctest.REPORT_CDIFF, doctest.REPORT_NDIFF, doctest.REPORT_ONLY_FIRST_FAILURE):

pytest --doctest-modules --doctest-report none
pytest --doctest-modules --doctest-report udiff
pytest --doctest-modules --doctest-report cdiff
pytest --doctest-modules --doctest-report ndiff
pytest --doctest-modules --doctest-report only_first_failure

Возможности pytest

Некоторые возможности упрощают написание doctests или обеспечивают более тесную интеграцию с существующим набором тестов. Однако учтите, что использование этих возможностей сделает ваши doctests несовместимыми со стандартным модулем doctests.

Использование фикстур

Фикстуры можно использовать с помощью вспомогательной функции getfixture:

# content of example.rst
>>> tmp = getfixture('tmp_path')
>>> ...
>>>

Обратите внимание: фикстура должна быть определена в месте, доступном pytest, например в файле conftest.py или плагине; обычные файлы Python с docstring обычно не сканируются в поисках фикстур, если это явно не настроено с помощью python_files.

При выполнении текстовых файлов doctest также поддерживаются маркер usefixtures и фикстуры с маркером autouse.

Модули doctest на Python собираются отдельно от тестовых файлов Python. Область действия фикстур между ними не общая.

Doctests не поддерживают фикстуры, зависящие от параметризации, поскольку при сборе doctest не генерируются тесты так же, как для обычных тестовых функций. Это касается и параметризованных фикстур autouse. Если нужно запускать doctests с несколькими бэкендами или конфигурациями, рассмотрите возможность перенести эти проверки в обычные тестовые функции или отдельный плагин doctest.

Фикстура ‘doctest_namespace’

Фикстура doctest_namespace позволяет добавлять объекты в пространство имён, в котором выполняются ваши doctests. Предполагается, что она будет использоваться в ваших фикстурах, чтобы предоставлять тестам, которые их используют, необходимый контекст.

doctest_namespace — это стандартный объект dict, в который помещаются объекты, доступные в пространстве имён doctest:

# content of conftest.py
import pytest
import numpy


@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
    doctest_namespace["np"] = numpy

после чего их можно напрямую использовать в doctests:

# content of numpy.py
def arange():
    """
    >>> a = np.arange(10)
    >>> len(a)
    10
    """

Обратите внимание: как и обычные conftest.py, фикстуры обнаруживаются в дереве каталогов, в котором находится conftest. Это значит, что если doctest находится рядом с исходным кодом, соответствующий conftest.py должен находиться в том же дереве каталогов. Фикстуры не будут обнаружены в соседнем дереве каталогов!

Пропуск тестов

По тем же причинам, по которым иногда нужно пропускать обычные тесты, можно пропускать и тесты внутри doctests.

Чтобы пропустить одну проверку внутри doctest, можно использовать стандартную директиву doctest.SKIP:

def test_random(y):
    """
    >>> random.random()  # doctest: +SKIP
    0.156231223

    >>> 1 + 1
    2
    """

Это пропустит первую проверку, но не вторую.

В doctests pytest также позволяет использовать стандартные функции pytest pytest.skip() и pytest.xfail(). Это может быть полезно, поскольку позволяет пропускать тесты или помечать их как ожидаемо падающие в зависимости от внешних условий:

>>> import sys, pytest
>>> if sys.platform.startswith('win'):
...     pytest.skip('this doctest does not work on Windows')
...
>>> import fcntl
>>> ...

Однако использовать эти функции не рекомендуется, поскольку это снижает удобочитаемость docstring.

Примечание

Поведение pytest.skip() и pytest.xfail() различается в зависимости от того, находятся ли doctests в файле Python (в docstring) или в текстовом файле, где doctests перемежаются с текстом:

  • Модули Python (docstring): функции действуют только в соответствующем docstring, а остальные docstring в том же модуле выполняются как обычно.
  • Текстовые файлы: функции пропускают проверки или помечают их как ожидаемо падающие до конца всего файла.

Альтернативы

Встроенная поддержка doctest в pytest предоставляет широкий набор возможностей, но если вы активно используете doctests, вам могут быть интересны внешние пакеты, которые добавляют множество функций и интегрируются с pytest:

  • pytest-doctestplus: предоставляет расширенную поддержку doctest и позволяет тестировать файлы reStructuredText («.rst»).
  • Sybil: позволяет тестировать примеры в документации, извлекая их из исходного текста документации и выполняя в рамках обычного запуска тестов.

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

Spec-Zone.ru

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