9、pytest -- 集成文档测试
目录
1. 集成doctest
模块
是python
内置的一个标准库,它可以查找代码中类似交互式会话形式的注释,并检查它们是否正确;
1.1. 通过指定文本文件的方式
默认情况下,pytest
会自动收集所有名称匹配test*.txt
规则的文件,并调用doctest
执行它们;
下面,我们来看一个简单的例子:
# src/chapter-9/test_example.txt >>> x = 3 >>> x 3
直接使用pytest
命令就可以执行它:
λ pipenv run pytest src/chapter-9/test_example.txt ====================== test session starts ======================= platform win32 -- python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0 rootdir: d:\personal files\projects\pytest-chinese-doc collected 1 item src\chapter-9\test_example.txt . [100%] ======================= 1 passed in 0.03s ========================
我们也可以使用命令行选项--doctest-glob
添加文件名称的匹配规则;
例如,匹配rst
格式的文件:
pytest --doctest-glob='*.rst'
注意:
--doctest-glob
可以多次指定,它们之间是或者的关系,并且依旧支持默认的test*.txt
规则;
1.1.1. 文本文件的编码
doctest
文件的默认编码是utf-8,你可以在pytest.ini
中使用doctest_encoding
选项指定新的编码;例如,使用latin1
编码:
[pytest] doctest_encoding = latin1
1.2. 通过编写文档字符串的方式
除了文本文件外,pytest
还支持检查文档字符串中的注释;例如:
# src/chapter-9/test_module.py def something(): '''文档字符串示例 >>> something() 42 ''' return 42 def test_module(): assert something() == 42
执行时,需要添加--doctest-modules
命令行选项:
λ pipenv run pytest --doctest-modules src/chapter-9/test_module.py ====================== test session starts ======================= platform win32 -- python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0 rootdir: d:\personal files\projects\pytest-chinese-doc collected 2 items src\chapter-9\test_module.py .. [100%] ======================= 2 passed in 0.03s ========================
--doctest-modules
会查找所有名称匹配*.py
的文件,收集文档字符串中类似交互式会话形式的注释,并把每一个文档字符串作为一个用例来执行,所以上面我们执行了两个测试,其中一个是文档测试;
如果想让pytest --doctest-modules
正确收集到相关注释,需满足以下条件:
- 文件名称符合
*.py
规则,但无需满足test_*.py
或者*_test.py
规则; - 文档字符串中的注释必须是类似
python
交互式会话形式的注释;
如果你不想每次执行都指定--doctest-modules
选项,可以考虑在pytest.ini
中添加如下配置:
[pytest] addopts = --doctest-modules
文档字符串是一个多行字符串,使用
'''
或者"""
包裹;一般推荐形式为,第一行简述功能,第二行空行,第三行具体描述;并且,可以通过
__doc__
属性访问它;例如,上面例子的__doc__
属性为:>>> print(something.__doc__) 文档字符串示例 >>> something() 42
1.3. 指定额外的选项
1.3.1. doctest
标准库自带的选项
python
的doctest
标准库自带一些选项,用于定义文档测试的模式,我们同样可以在pytest.ini
中使用这些功能;例如,忽略尾随的空格:
# src/chapter-9/pytest.ini doctest_optionflags = normalize_whitespace
另外,你也可以在行注释中使能这些选项;
例如,使用# doctest: +normalize_whitespace
同样能忽略尾随的空格:
def something(): '''文档字符串示例 >>> something() # doctest: +normalize_whitespace 42 ''' return 42
更多细节可以参考:
1.3.2. pytest
自有的选项
allow_bytes
:在输出时,剔除字符串的b
前缀;例如,以下文档测试是成功的:
# src/chapter-9/options.py def str_bytes(): '''返回字节编码 >>> str_bytes() # doctest: +allow_bytes 'bytes' ''' return b'bytes'
allow_unicode
:相似的,在输出时,剔除字符串的u
前缀;
number
:为了避免出现以下导致测试失败的情况:
expected: 3.14 got: 3.141592653589793
我们可以通过配置number
选项,只比较列出的精度:
# src/chapter-9/options.py def number(): '''浮点数的精度 >>> import math >>> math.pi # doctest: +number 3.14 ''' return 1
注意:我们并不建议在全局使能
number
选项,因为它会修改输出中所有的浮点数的精度,甚至是在字符串或者列表中;例如,以下文档测试也是成功的:
# src/chapter-9/options.py def str_number(): '''浮点数字符串的精度 >>> str_number() # doctest: +number '3.14' ''' return '3.1415'
2. 失败时继续执行
默认情况下,对于一个给定的文档测试,pytest
在遇到第一个失败点时退出执行;但是,我们可以通过--doctest-continue-on-failure
命令行选项,让其继续执行;
例如,对于以下文档字符串,包含两个测试点,pytest --doctest-continue-on-failure
会报告两个错误(默认只会报告第一个错误):
def str_bytes(): '''返回字节编码 >>> str_bytes() 'bytes' >>> import math >>> math.pi 3.14 ''' return b'bytes'
3. 指定输出的格式
文档测试失败时,你可以通过以下方式更改测试输出的格式:
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
更多细节可以参考:https://docs.python.org/3/library/doctest.html#doctest.report_udiff
4. 文档测试中使用fixture
通过getfixture
可以让你在文档字符串中使用fixture
:
>>> tmp = getfixture('tmpdir') >>> ... >>>
5. 文档测试的命名空间
doctest_namespace fixture
可以用于向运行doctest
测试的命名空间中注入一些信息,它是一个标准的字典对象;
例如,我们在conftest.py
中定义一个方法,注入到doctest
的命名空间中:
# src/chapter-9/conftest.py import pytest def func(): return 42 @pytest.fixture(autouse=true) def add_func(doctest_namespace): doctest_namespace['function'] = func
可以在文档字符串中直接使用它:
# src/chapter-9/func.txt >>> function() 42
6. 跳过文档测试
pytest 4.4
版本新增功能
我们可以通过pytest.skip
跳过文档测试;例如,跳过windows
系统上的文档测试:
>>> import sys, pytest >>> if sys.platform.startswith('win'): ... pytest.skip('this doctest does not work on windows') >>> function() 42
github仓库地址:
上一篇: Python语言控制运算的优先级