欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

9、pytest -- 集成文档测试

程序员文章站 2022-05-22 16:46:39
pytest 可以集成 python 内置的 doctest 标准库,用于文档测试,并有多种使用形式和定制化的选项; ......

目录

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标准库自带的选项

pythondoctest标准库自带一些选项,用于定义文档测试的模式,我们同样可以在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仓库地址: