译者注:doctest是python标准的模块,如果要了解相关的知识可以百度doctest
默认情况下,所有符合 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-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item
test_example.txt . [100%]
============================ 1 passed in 0.12s =============================

译者注:在txt文件中,>>> x 表示输出x,下面的3表示期望值是3,如果x是3,则测试通过,不是3,则测试失败

默认情况下,pytest会收集test*.txt文件寻找doctest指令,你也可以使用 --doctest-glob 指令来传递一个额外的设置。
除了文本文件,你还可以直接从类,函数,模块的docstring中执行doctest:

# 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-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 2 items
mymodule.py . [ 50%]
test_example.txt . [100%] ============================ 2 passed in 0.12s =============================

你可以在你的项目中固化这些设置,方法是写在 pytest.ini 中:

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

注意:pytest内置的doctest只支持doctest块,如果你想在所有的文档中执行更高级的检查,你需要引用 … codeblock:: python Sphinx指令支持,如果你的文档中包含其他例子,你可能会考虑 Sybil。它提供了一个开箱即用的pytest集成。

11.1 编码

默认的编码是UTF-8,你可以在pytest.ini中指定文档测试文件的编码方式:

# content of pytest.ini
[pytest]
doctest_encoding = latin1

11.2 使用 ‘doctest’ 配置

Python 的标准 doctest 模块提供了一些选项来配置文档测试的严格程度。在pytest中,你可以在配置文件中启用这些配置:

[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 前缀会被剥离。这是为了代码可以运行在 Python2和Python3中而无需修改。
  • ALLOW_BYTES:同样的,期望值中的 b 前缀会被剥离
  • NUMBER:启用之后,浮点型的数字只需要能够匹配写出的精度。例如,下面的输出只需要匹配2位小数:
>>> math.pi
3.14

如果你写了 3.1416,则真实值就需要匹配四位小鼠,以此类推。
这避免了由于浮点数精度引起的误报,像这样:

Expected:
0.233
Got:
0.23300000000000001

NUMBER 也支持一个浮点数的列表,事实上,他会对所有出现的浮点数都生效,即使是在字符串中!这就意味着它可能不适合于在配置文件中全局启用它。

5.1版本新增。

11.3 失败后继续

默认情况下,pytest只报告第一个失败的doctest,如果你想在测试失败的时候继续,你需要做:

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

11.4 输出格式

你可以使用标准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

11.5 pytest 的特殊功能

下面这些功能是为了让你更轻松的编写文档测试或是更好的与已有的测试用例集成。但是要记着这些功能会让你的文档测试与标准的文档测试模块不兼容:

11.5.1 使用夹具

可以在文档测试中使用夹具:

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

注意,夹具必须定义在可以被pytest发现的地方,如 conftest.py 或者插件中;普通含有文档测试的py文件不会自动扫描夹具,除非在配置文件的 python_files 中专门配置过。同时,在执行文档测试的时候,使用usefixtures定义的和标记了autouse自动使用的夹具会被支持。

11.5.2 ‘doctest_namespace’夹具

doctest_namespace夹具可以用来向运行的doctests命名空间植入项目。这被用来在自己的夹具中为将要使用这个夹具的文档测试提供命名空间上下文的支持。doctest_namespace是一个标准的字典对象,里面放着你期望在文档测试中出现的命名空间:

# content of conftest.py
import numpy

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

然后就可以在之后的文档测试中直接使用:

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

注意像 conftest.py一样,在conftest所在的目录中的夹具会被发现。意思是如果你要将你的文档测试和代码组织起来,相关的 conftest.py 需要被放到相同的目录下。夹具不会被同级的兄弟目录发现。

11.5.3 动态的跳过测试

4.4版本新增。
你可以使用 pytest.skip 动态的跳过文档测试,例如:

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