历史笔记

此页列出了Pytest以前版本的特性或行为,这些特性或行为在过去几年中发生了变化。它们作为历史记录保存在这里,因此查看旧代码的用户可以找到与它们相关的文档。

标记更新和迭代

在 3.6 版更改.

Pytest的标记实现传统上只需更新 __dict__ 函数的属性,用于累积添加标记。因此,标记会无意中以令人惊讶的方式沿着类层次结构传递。此外,用于检索它们的API不一致,因为来自参数化的标记的存储方式与使用 @pytest.mark 通过添加装饰和标记 node.add_marker .

这种状态使得在技术上几乎不可能在不深入了解内部情况的情况下正确地使用来自标记的数据,从而导致更高级的用法中出现微妙且难以理解的错误。

根据标记的声明/更改方式,可以得到 MarkerInfo 可能包含来自兄弟类的标记, MarkDecorators 当标记来自参数化或 node.add_marker 呼叫,丢弃先前的标记。阿尔索 MarkerInfo 当它实际上表示具有相同名称的多个标记上的合并视图时,它就像一个标记。

除此之外,模块、类和函数/方法无法以同样的方式访问这些标记。事实上,标记只能在函数中访问,即使它们是在类/模块上声明的。

Pytest 3.6引入了一种新的访问标记API,以解决初始设计中的问题,提供了 _pytest.nodes.Node.iter_markers() 方法对标记进行一致的迭代,并对内部结构进行修改,解决了初始设计中的许多问题。

更新代码

老年人 Node.get_marker(name) 函数被视为已弃用,因为它返回内部 MarkerInfo 包含合并名称的对象, *args**kwargs 应用于该节点的所有标记中。

一般来说,关于如何处理标记有两种情况:

1。标记相互覆盖。订购很重要,但你只想把你的标记看作一个单独的项目。例如。 log_level('info') 在模块级,可以被覆盖 log_level('debug') 用于特定测试。

在这种情况下,使用 Node.get_closest_marker(name)

# replace this:
marker = item.get_marker("log_level")
if marker:
    level = marker.args[0]

# by this:
marker = item.get_closest_marker("log_level")
if marker:
    level = marker.args[0]

2。标记以附加方式组成。例如。 skipif(condition) 标记意味着你只想评估所有的标记,顺序甚至不重要。你可能想把你的分数看作一组。

在本例中,迭代每个标记并处理它们的 *args**kwargs 个别地。

# replace this
skipif = item.get_marker("skipif")
if skipif:
    for condition in skipif.args:
        # eval condition
        ...

# by this:
for skipif in item.iter_markers("skipif"):
    condition = skipif.args[0]
    # eval condition

如果您不确定或有任何问题,请考虑开始 an issue .

缓存插件集成到核心中

的功能 core cache 插件以前作为名为 pytest-cache . 核心插件在命令行选项和API使用方面是兼容的,只是您只能在JSON可序列化的测试运行之间存储/接收数据。

福卡斯和 pytest_funcarg__

在2.3之前的版本中没有 @pytest.fixture 马克和你必须使用魔法 pytest_funcarg__NAME 夹具工厂的前缀。这仍然并将保持支持,但不再作为声明fixture函数的主要方法进行宣传。

@pytest.yield_fixture decorator

在版本2.10之前,为了使用 yield 执行拆卸代码的语句必须使用 yield_fixture 标记。从2.10开始,普通夹具可以使用 yield 直接如此 yield_fixture 修饰符不再需要,并被视为已弃用。

[pytest] header in setup.cfg

在3.0之前,支持的节名称是 [pytest] . 由于这可能与某些distutils命令冲突,建议使用 setup.cfg 文件现在 [tool:pytest] .

请注意 pytest.initox.ini 文件分区名称是 [pytest] .

将标记应用于 @pytest.mark.parametrize 参数

在3.1版之前,支持的标记值的机制使用了以下语法:

import pytest


@pytest.mark.parametrize(
    "test_input,expected", [("3+5", 8), ("2+4", 6), pytest.mark.xfail(("6*9", 42))]
)
def test_eval(test_input, expected):
    assert eval(test_input) == expected

这是一个支持该特性的初始攻击,但很快就被证明是不完整的,因为传递函数或应用具有相同名称但不同参数的多个标记而被破坏。

计划在Pytest-4.0中删除旧语法。

@pytest.mark.parametrize 参数名作为元组

在2.4之前的版本中,需要将参数名指定为元组。这仍然有效,但更简单 "name1,name2,..." 逗号分隔的字符串语法现在首先公布,因为它更容易编写,并且产生的行噪声更小。

设置:现在是“自动使用装置”

在Pytest-2.3之前的开发过程中,发布名称 pytest.setup 被使用,但在释放之前,它被重新命名并移动成为通用夹具机制的一部分,即 自动使用设备(您不必请求设备)

条件是字符串而不是布尔值

在pytest-2.4之前,指定skipif/xfail条件的唯一方法是使用字符串:

import sys


@pytest.mark.skipif("sys.version_info >= (3,3)")
def test_function():
    ...

在测试函数设置过程中,通过调用 eval('sys.version_info >= (3,0)', namespace) . 命名空间包含所有模块全局,以及 ossys 最低限度。

自Pytest-2.4 boolean conditions 因为标记可以在测试模块之间自由导入,所以被认为更可取。对于字符串,您不仅需要导入标记,还需要导入标记使用的所有变量,这违反了封装。

将条件指定为字符串的原因是 pytest 只能基于条件字符串报告跳过条件的摘要。如果条件为布尔值,则需要指定 reason 字符串。

注意,字符串条件将保持完全支持,如果不需要交叉导入标记,您可以自由使用它们。

条件字符串的计算 pytest.mark.skipif(conditionstring)pytest.mark.xfail(conditionstring) 发生在命名空间字典中,其构造如下:

  • 通过将 sysos 模块和Pytest config 对象进入它。

  • 用应用表达式的测试函数的模块全局更新。

彼得 config 对象允许您根据可能添加的测试配置值跳过:

@pytest.mark.skipif("not config.getvalue('db')")
def test_function():
    ...

与“布尔条件”等价的是:

@pytest.mark.skipif(not pytest.config.getvalue("db"), reason="--db was not specified")
def test_function():
    pass

注解

不能使用 pytest.config.getvalue() 在pytest的参数解析发生之前导入的代码中。例如, conftest.py 在命令行分析之前导入文件,因此 config.getvalue() 无法正确执行。

pytest.set_trace()

在2.4版之前,在需要使用的代码中设置断点 pytest.set_trace()

import pytest


def test_function():
    ...
    pytest.set_trace()  # invoke PDB debugger and tracing

这已不再需要,人们可以使用本机 import pdb;pdb.set_trace() 直接调用。

有关详细信息,请参阅 设置断点 .

“compat”属性

访问 ModuleFunctionClassInstanceFileItem 通过 Node 实例一直被记录为已弃用,但开始从pytest发出警告 3.9 向前。

用户应该 import pytest 并使用 pytest 模块。