弃用和移除

此页面列出了当前已弃用或在过去的主要版本中已移除的所有 pytest 功能。目的是向用户明确说明弃用某个功能的原因,以及应该使用哪些替代方案。

已弃用的功能

以下是所有被认为已弃用的 pytest 功能的完整列表。使用这些功能将发出 PytestWarning 或其子类,可以使用 标准警告过滤器 对其进行筛选。

pytest.importorskip 关于 ImportError 的默认行为

自 8.2 版本起弃用。

传统上 pytest.importorskip() 将捕获 ImportError,其最初目的是跳过未安装依赖模块的测试,例如使用不同的依赖项进行测试。

但是,某些包可能已安装在系统中,但由于其他一些问题(例如编译错误或安装损坏)而无法导入。在这些情况下,pytest.importorskip() 仍会静默跳过测试,但大多数情况下用户希望看到意外错误,以便可以修复潜在问题。

8.2 中,添加了 exc_type 参数,使用户能够传递 ModuleNotFoundError,仅当无法真正找到模块时才跳过测试,而不是因为其他错误。

默认情况下仅捕获 ModuleNotFoundError(并让其他错误传播)将是最佳解决方案,但是为了向后兼容,pytest 将保留现有行为,但在以下情况下发出警告:

  1. 捕获的异常属于 ImportError 类型,并且

  2. 用户没有明确传递 exc_type

如果导入尝试引发 ModuleNotFoundError(通常情况),则跳过模块且不发出警告。

通过这种方式,通常情况下将继续以相同的方式工作,而意外错误现在将发出警告,用户可以通过明确传递 exc_type=ImportError 来抑制警告。

9.0 中,警告将变为错误,在 9.1 中,pytest.importorskip() 将仅默认捕获 ModuleNotFoundError,并且不再发出警告——但用户仍然可以通过将其传递给 exc_type 来捕获 ImportError

fspath 参数对于 Node 构造函数已替换为 pathlib.Path

自版本 7.0 起弃用。

为了支持从 py.path.localpathlib 的过渡,Node 构造函数(如 pytest.Function.from_parent()pytest.Class.from_parent())的 fspath 参数现已弃用。

构造节点的插件应传递 path 参数(类型为 pathlib.Path),而不是 fspath 参数。

鼓励实现自定义项和收集器的插件用 path 参数(pathlib.Path)替换 fspath 参数(py.path.local),并在可能的情况下放弃对 py 库的任何其他使用。

如果可能,带有自定义项的插件应使用协作构造函数来避免硬编码它们仅传递给超类的参数。

注意

Node参数和属性(新属性为path)的名称与钩子的情况相反如下所述(旧参数为path)。

这是一个不幸的人工制品,由于历史原因,随着我们逐渐摆脱py依赖项,它应该在未来版本中得到解决(请参阅问题 #9283以进行更长的讨论)。

由于仍在预期返回py.path.local对象的reportinfo()等方法的持续迁移,节点仍然同时具有fspath (py.path.local)和path (pathlib.Path)属性,无论在构造函数中使用了什么参数。我们希望在未来的版本中弃用fspath属性。

使用标记配置钩子规范/实现

在 pytest 的插件库 pluggy 成为其自己的包并拥有明确的 API 之前,pytest 仅使用pytest.mark来配置钩子。

装饰器pytest.hookimpl()pytest.hookspec()已经可用多年,应该改用它们。

@pytest.mark.tryfirst
def pytest_runtest_call(): ...


# or
def pytest_runtest_call(): ...


pytest_runtest_call.tryfirst = True

应更改为

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_call(): ...

已更改的hookimpl属性

  • tryfirst

  • trylast

  • optionalhook

  • hookwrapper

已更改的hookwrapper属性

  • firstresult

  • historic

py.path.local参数已替换为pathlib.Path

自版本 7.0 起弃用。

为了支持从py.path.localpathlib的过渡,以下钩子现在接收附加参数

随附的 py.path.local 路径已弃用:手动调用这些钩子的插件应该只传递新的 pathlib.Path 参数,用户应该更改其钩子实现以使用新的 pathlib.Path 参数。

注意

Node 参数和属性的名称,如上所述(新属性为 path)与钩子的情况相反(旧参数为 path)。

这是一个不幸的人工制品,由于历史原因,随着我们逐渐摆脱py依赖项,它应该在未来版本中得到解决(请参阅问题 #9283以进行更长的讨论)。

直接构造内部类

自版本 7.0 起弃用。

现在弃用直接构造以下类

  • _pytest.mark.structures.Mark

  • _pytest.mark.structures.MarkDecorator

  • _pytest.mark.structures.MarkGenerator

  • _pytest.python.Metafunc

  • _pytest.runner.CallInfo

  • _pytest._code.ExceptionInfo

  • _pytest.config.argparsing.Parser

  • _pytest.config.argparsing.OptionGroup

  • _pytest.pytester.HookRecorder

这些构造函数一直被认为是私有的,但现在会发出弃用警告,这可能会在 pytest 8 中变成一个硬错误。

pytest.Collectorpytest.Item 之间的菱形继承

自版本 7.0 起弃用。

定义一个自定义的 pytest 节点类型,它既是 Item 又是一个 Collector(例如 File),现在会发出警告。它从未得到合理的支持,并且会触发难以调试的错误。

一些提供 linting/代码分析的插件已将其用作一种 hack。相反,应使用一个单独的收集器节点,它收集项目。请参阅 使用非 Python 测试 以获取示例,以及一个 修复继承的示例 pr

自定义 Node 子类的构造函数应采用 **kwargs

自版本 7.0 起弃用。

如果 pytest.Item 等节点的自定义子类覆盖 __init__ 方法,它们应采用 **kwargs。因此,

class CustomItem(pytest.Item):
    def __init__(self, name, parent, additional_arg):
        super().__init__(name, parent)
        self.additional_arg = additional_arg

应变为

class CustomItem(pytest.Item):
    def __init__(self, *, additional_arg, **kwargs):
        super().__init__(**kwargs)
        self.additional_arg = additional_arg

以避免对 pytest 可以传递给超类的参数进行硬编码。请参阅 使用非 Python 测试 以获取完整示例。

对于没有冲突的情况,不会发出弃用警告。对于有冲突的情况(例如 pytest.File 现在采用 path 而不是 fspath,如 上面概述),现在会发出弃用警告。

将标记应用于 fixture 函数

已弃用,版本 7.4 起。

将标记应用于 fixture 函数从未产生任何效果,但这是一个常见的用户错误。

@pytest.mark.usefixtures("clean_database")
@pytest.fixture
def user() -> User: ...

在这种情况下,用户期望 usefixtures 标记会产生预期效果,即在调用 user 时使用 clean_database fixture,但实际上它根本没有任何效果。

现在,当 pytest 遇到此问题时,它会发出警告,并在未来版本中引发错误。

在测试函数中返回非 None 值

已弃用,版本 7.2 起。

如果测试函数返回 None 以外的内容,现在会发出 pytest.PytestReturnNotNoneWarning

这可以防止初学者常见的错误,即期望返回 bool 会导致测试通过或失败,例如

@pytest.mark.parametrize(
    ["a", "b", "result"],
    [
        [1, 2, 5],
        [2, 3, 8],
        [5, 3, 18],
    ],
)
def test_foo(a, b, result):
    return foo(a, b) == result

鉴于 pytest 忽略返回值,因此它永远不会失败可能会令人惊讶。

正确的修复方法是将 return 更改为 assert

@pytest.mark.parametrize(
    ["a", "b", "result"],
    [
        [1, 2, 5],
        [2, 3, 8],
        [5, 3, 18],
    ],
)
def test_foo(a, b, result):
    assert foo(a, b) == result

函数/装饰器 yield_fixture

自版本 6.2 起弃用。

pytest.yield_fixturepytest.fixture() 的弃用别名。

它已经弃用很长时间了,因此可以安全地搜索/替换。

已移除功能和重大更改

如我们的 向后兼容性政策 政策中所述,弃用的功能仅在经过适当的弃用期后才会在主要版本中移除。

还列出了一些无法弃用的重大更改。

为 nose 编写的测试提供支持

已弃用,版本 7.2 起。

在版本 8.0 中移除。

nose 编写的测试提供运行支持现已弃用。

nose 多年来一直处于仅维护模式,并且维护插件并非易事,因为它会溢出代码库(有关更多详细信息,请参见 问题 #9886)。

setup/teardown

可能会让用户感到意外的一件事是,普通的 setupteardown 方法并非 pytest 原生,它们实际上是 nose 支持的一部分。

class Test:
    def setup(self):
        self.resource = make_resource()

    def teardown(self):
        self.resource.close()

    def test_foo(self): ...

    def test_bar(self): ...

原生 pytest 支持使用 setup_methodteardown_method(请参见 方法和函数级别的 setup/teardown),因此上述内容应更改为

class Test:
    def setup_method(self):
        self.resource = make_resource()

    def teardown_method(self):
        self.resource.close()

    def test_foo(self): ...

    def test_bar(self): ...

可以通过执行简单的查找/替换在整个代码库中轻松完成此操作。

@with_setup

使用 @with_setup 的代码,例如

from nose.tools import with_setup


def setup_some_resource(): ...


def teardown_some_resource(): ...


@with_setup(setup_some_resource, teardown_some_resource)
def test_foo(): ...

还需要移植到受支持的 pytest 样式。一种方法是使用固定装置

import pytest


def setup_some_resource(): ...


def teardown_some_resource(): ...


@pytest.fixture
def some_resource():
    setup_some_resource()
    yield
    teardown_some_resource()


def test_foo(some_resource): ...

属性 compat_co_firstlineno

Nose 检查函数对象上的此属性以允许覆盖函数的推断行号。Pytest 不再尊重此属性。

pytest.skippytest.failpytest.exit 传递 msg=

自版本 7.0 起弃用。

在版本 8.0 中移除。

现在弃用向 pytest.skip()pytest.fail()pytest.exit() 传递关键字参数 msg,而应改用 reason。此更改是为了使这些函数与已接受 reason 参数的 @pytest.mark.skip@pytest.mark.xfail 标记保持一致。

def test_fail_example():
    # old
    pytest.fail(msg="foo")
    # new
    pytest.fail(reason="bar")


def test_skip_example():
    # old
    pytest.skip(msg="foo")
    # new
    pytest.skip(reason="bar")


def test_exit_example():
    # old
    pytest.exit(msg="foo")
    # new
    pytest.exit(reason="bar")

收集器 pytest.Instance

在版本 7.0 中移除。

已移除 pytest.Instance 收集器类型。

以前,Python 测试方法作为 Class -> Instance -> Function 收集。现在 Class 直接收集测试方法。

大多数引用 Instance 的插件都会使用 if isinstance(node, Instance): return 这样的检查来忽略或跳过它。此类插件应该在 pytest>=7 中简单地删除对 Instance 的考虑。但是,为了保持此类用法正常工作,已在 pytest.Instance_pytest.python.Instance 中实例化了一个虚拟类型,并且导入它会发出弃用警告。此功能已在 pytest 8 中删除。

使用 pytest.warns(None)

自版本 7.0 起弃用。

在版本 8.0 中移除。

pytest.warns(None) 现已弃用,因为它经常被滥用。其正确用法是检查代码是否发出任何类型的至少一个警告 - 如 pytest.warns()pytest.warns(Warning)

有关示例,请参阅 测试中警告的其他用例

Parser.addoption 中向后兼容

自版本 2.4 起弃用。

在版本 8.0 中移除。

Parser.addoption 的几种行为现已在 pytest 8 中删除(自 pytest 2.4.0 起弃用)

  • parser.addoption(..., help=".. %default ..") - 改用 %(default)s

  • parser.addoption(..., type="int/string/float/complex") - 改用 type=int 等。

命令行选项 --strict

自版本 6.2 起弃用。

在版本 8.0 中移除。

命令行选项 --strict 已弃用,取而代之的是 --strict-markers,它更好地传达了该选项的作用。

我们计划在未来重新引入 --strict,并使其成为所有严格相关选项(目前为 --strict-markers--strict-config)的包罗万象标志,未来可能会引入更多标志。

实现 pytest_cmdline_preparse 挂钩

自版本 7.0 起弃用。

在版本 8.0 中移除。

实现 pytest_cmdline_preparse 挂钩已被正式弃用。改而实现 pytest_load_initial_conftests 挂钩。

def pytest_cmdline_preparse(config: Config, args: List[str]) -> None: ...


# becomes:


def pytest_load_initial_conftests(
    early_config: Config, parser: Parser, args: List[str]
) -> None: ...

pytest 8 中的收集更改

添加了一个新的 pytest.Directory 基本收集节点,预计文件系统目录的所有收集器节点都将作为其子类。这类似于现有的 pytest.File 文件节点。

pytest.Package 更改为 pytest.Directory 的子类。 Package 表示一个文件系统目录,它是一个 Python 包,即包含一个 __init__.py 文件。

pytest.Package 现在只收集其自身目录中的文件;以前它会递归收集。子目录作为子收集器节点收集,从而创建一个与文件系统层次结构相似的收集树。

session.name 现在是 "";以前它是根目录目录名称。这与 session.nodeid 相匹配,后者一直是 ""

添加了一个新的 pytest.Dir 具体收集节点,它是 pytest.Directory 的子类。此节点表示一个文件系统目录,它不是 pytest.Package,即不包含 __init__.py 文件。与 Package 类似,它只收集其自身目录中的文件,同时将子目录收集为子收集器节点。

文件和目录现在按字母顺序联合收集,除非插件进行了更改。以前,文件在目录之前收集。

收集树现在包含 rootdir 中的目录/包,对于在 rootdir 中找到的初始参数。对于 rootdir 之外的文件,只收集直接的目录/包——但请注意,不建议在 rootdir 之外收集。

例如,给定以下文件系统树

myroot/
    pytest.ini
    top/
    ├── aaa
    │   └── test_aaa.py
    ├── test_a.py
    ├── test_b
    │   ├── __init__.py
    │   └── test_b.py
    ├── test_c.py
    └── zzz
        ├── __init__.py
        └── test_zzz.py

收集树,如 pytest --collect-only top/ 所示,但添加了原本隐藏的 Session 节点以提高清晰度,现在如下所示

<Session>
  <Dir myroot>
    <Dir top>
      <Dir aaa>
        <Module test_aaa.py>
          <Function test_it>
      <Module test_a.py>
        <Function test_it>
      <Package test_b>
        <Module test_b.py>
          <Function test_it>
      <Module test_c.py>
        <Function test_it>
      <Package zzz>
        <Module test_zzz.py>
          <Function test_it>

以前,它是

<Session>
  <Module top/test_a.py>
    <Function test_it>
  <Module top/test_c.py>
    <Function test_it>
  <Module top/aaa/test_aaa.py>
    <Function test_it>
  <Package test_b>
    <Module test_b.py>
      <Function test_it>
  <Package zzz>
    <Module test_zzz.py>
      <Function test_it>

依赖于收集树特定形状的代码/插件可能需要更新。

pytest.Package 不再是 pytest.Modulepytest.File

在版本 8.0 中更改。

Package 采集器节点指定一个 Python 包,即一个包含 __init__.py 文件的目录。之前, Packagepytest.Module(表示单个 Python 模块)的一个子类型,该模块是 __init__.py 文件。这被认为是一个设计错误(有关详细信息,请参见 问题 #11137问题 #7777)。

Package 节点的 path 属性现在指向包目录,而不是 __init__.py 文件。

请注意,如果在收集期间选取了 __init__.py(不是 Package)的 Module 节点,则该节点可能仍然存在(例如,如果您将 python_files 配置为包含 __init__.py 文件)。

不再收集 __init__.py 文件的包

在版本 8.0 中移除。

现在运行 pytest pkg/__init__.py 仅收集 pkg/__init__.py 文件(模块)。之前,它收集整个 pkg 包,包括目录中的其他测试文件,但不包括 __init__.py 文件本身中的测试(除非将 python_files 更改为允许 __init__.py 文件)。

要收集整个包,只需指定目录: pytest pkg

pytest.collect 模块

自 6.0 版本起不推荐使用。

在版本 7.0 中移除。

pytest.collect 模块不再是公共 API 的一部分,现在应直接从 pytest 导入其所有名称。

pytest_warning_captured 钩子

自 6.0 版本起不推荐使用。

在版本 7.0 中移除。

此钩子有一个 item 参数,该参数无法由 pytest-xdist 序列化。

请改用 pytest_warning_recorded 钩子,它将 item 参数替换为 nodeid 参数。

pytest._fillfuncargs 函数

自 6.0 版本起不推荐使用。

在版本 7.0 中移除。

此功能保留是为了与旧插件保持向后兼容性。

它的功能并不意味着直接使用,但如果您必须替换它,请使用 function._request._fillfixtures(),但请注意这不是一个公共 API,将来可能会中断。

--no-print-logs 命令行选项

自 5.4 版本起弃用。

在 6.0 版本中删除。

已删除 --no-print-logs 选项和 log_print ini 设置。如果您使用它们,请改用 --show-capture

pytest 3.5.0 中添加了 --show-capture 命令行选项,它允许指定在测试失败时如何显示捕获的输出:nostdoutstderrlogall(默认值)。

结果日志 (--result-log)

自 4.0 版本起弃用。

在 6.0 版本中删除。

--result-log 选项会生成一个测试报告流,可以在运行时进行分析,但它使用一种自定义格式,要求用户实现自己的解析器。

pytest-reportlog 插件提供了一个 --report-log 选项,这是一个更标准且可扩展的替代方案,每行生成一个 JSON 对象,并且应该涵盖相同的使用案例。请尝试一下并提供反馈。

pytest-reportlog 插件甚至可能在某个时候合并到核心,具体取决于插件的计划和使用它的用户数量。

pytest_collect_directory 钩子

在 6.0 版本中删除。

pytest_collect_directory 钩子多年来一直无法正常工作(它被调用,但结果被忽略)。用户可以考虑改用 pytest_collection_modifyitems

TerminalReporter.writer

在 6.0 版本中删除。

TerminalReporter.writer 属性已弃用,不应再使用。这在无意中作为该插件的公共 API 的一部分公开,并将其与 py.io.TerminalWriter 联系得太紧密。

直接使用 TerminalReporter.writer 的插件应该改用提供相同功能的 TerminalReporter 方法。

junit_family 默认值更改为 “xunit2”

在 6.0 版本中更改。

在 pytest 6.0 中,junit_family 选项的默认值将更改为 xunit2,这是旧 xunit1 格式的更新,并且在默认情况下受操作此类文件(例如,Jenkins、Azure Pipelines 等)的现代工具支持。

建议用户尝试新的 xunit2 格式,并查看使用 JUnit XML 文件的工具是否支持它。

要使用新格式,请更新 pytest.ini

[pytest]
junit_family=xunit2

如果您发现您的工具不支持新格式,并且希望继续使用旧版本,请将选项设置为 legacy

[pytest]
junit_family=legacy

通过使用 legacy,在升级到 pytest 6.0 时,您将继续使用旧版/xunit1 格式,其中默认格式将是 xunit2

为了让用户了解转换,如果在命令行中给出了 --junit-xml 选项,但在 pytest.ini 中未明确配置 junit_family,pytest 将发出警告。

已知支持 xunit2 格式的服务

节点构造已更改为 Node.from_parent

在 6.0 版本中更改。

现在,节点的构造应使用命名构造函数 from_parent。API 表面中的此限制旨在实现对收集树的更好/更简单的重构。

这意味着,现在必须调用 MyItem.from_parent(collector, name="foo"),而不是 MyItem(name="foo", parent=collector, obj=42)

希望支持旧版 pytest 并抑制警告的插件可以使用 hasattr 检查 from_parent 是否存在于该版本中

def pytest_pycollect_makeitem(collector, name, obj):
    if hasattr(MyItem, "from_parent"):
        item = MyItem.from_parent(collector, name="foo")
        item.obj = 42
        return item
    else:
        return MyItem(name="foo", parent=collector, obj=42)

请注意,from_parent 仅应与参数的关键字参数一起调用。

pytest.fixture 参数仅为关键字

在 6.0 版本中删除。

已删除将参数作为位置参数传递给 pytest.fixture() 的操作 - 请改用关键字传递它们。

funcargnamesfixturenames 的别名

在 6.0 版本中删除。

FixtureRequestMetafuncFunction 类跟踪其关联 fixture 的名称,具有恰当命名的 fixturenames 属性。

在 pytest 2.3 之前,此属性名为 funcargnames,并且自那以后,我们一直将其保留为别名。它最终会被删除,因为它通常在插件作者必须区分 fixture 名称和非 fixture 事物(例如 pytest.mark.parametrize)提供的名称的地方造成混淆。

pytest.config 全局

在版本 5.0 中已删除。

pytest.config 全局对象已弃用。请改用 request.config(通过 request 固定装置)或者如果您是插件作者,请使用 pytest_configure(config) 挂钩。请注意,许多挂钩也可以通过 session.configitem.config 间接访问 config 对象。

"message" pytest.raises 的参数

在版本 5.0 中已删除。

认为此参数将匹配异常消息是一个常见的错误,而实际上它仅在 pytest.raises 检查失败时提供自定义消息。为了防止用户犯此错误,并且由于认为它用处不大,pytest 正在弃用它,目前不提供替代方案。

如果您有此参数的有效用例,请考虑您可以只在 with 语句的末尾手动调用 pytest.fail 来获得相同的结果。

例如

with pytest.raises(TimeoutError, message="Client got unexpected message"):
    wait_for(websocket.recv(), 0.5)

变为

with pytest.raises(TimeoutError):
    wait_for(websocket.recv(), 0.5)
    pytest.fail("Client got unexpected message")

如果您仍然担心此弃用和未来删除,请在 问题 #3974 中发表评论。

raises / warns,第二个参数为字符串

在版本 5.0 中已删除。

请改用这些的上下文管理器形式。必要时,直接调用 exec

示例

pytest.raises(ZeroDivisionError, "1 / 0")
pytest.raises(SyntaxError, "a $ b")

pytest.warns(DeprecationWarning, "my_function()")
pytest.warns(SyntaxWarning, "assert(1, 2)")

变为

with pytest.raises(ZeroDivisionError):
    1 / 0
with pytest.raises(SyntaxError):
    exec("a $ b")  # exec is required for invalid syntax

with pytest.warns(DeprecationWarning):
    my_function()
with pytest.warns(SyntaxWarning):
    exec("assert(1, 2)")  # exec is used to avoid a top-level warning

在自定义收集器中使用 Class

在版本 4.0 中已删除。

使用名为 "Class" 的对象作为自定义 Collector 子类中收集的节点类型的途径已弃用。用户应改用 pytest_pycollect_makeitem 在收集期间自定义节点类型。

此问题只应影响创建新收集类型的高级插件,因此如果您看到此警告消息,请联系作者,以便他们可以更改代码。

pytest.mark.parametrize 中的标记

在版本 4.0 中已删除。

现在弃用向 pytest.mark.parametrize 调用的值应用标记。例如

@pytest.mark.parametrize(
    "a, b",
    [
        (3, 9),
        pytest.mark.xfail(reason="flaky")(6, 36),
        (10, 100),
        (20, 200),
        (40, 400),
        (50, 500),
    ],
)
def test_foo(a, b): ...

此代码将 pytest.mark.xfail(reason="flaky") 标记应用于上述参数化调用的 (6, 36) 值。

这被认为难以阅读和理解,而且其实现给代码带来了问题,从而阻止了标记架构的进一步内部改进。

要更新代码,请使用 pytest.param

@pytest.mark.parametrize(
    "a, b",
    [
        (3, 9),
        pytest.param(6, 36, marks=pytest.mark.xfail(reason="flaky")),
        (10, 100),
        (20, 200),
        (40, 400),
        (50, 500),
    ],
)
def test_foo(a, b): ...

pytest_funcarg__ 前缀

在版本 4.0 中已删除。

在非常早期的 pytest 版本中,可以使用 pytest_funcarg__ 前缀来定义固定装置

def pytest_funcarg__data():
    return SomeData()

切换到 @pytest.fixture 装饰器

@pytest.fixture
def data():
    return SomeData()

[pytest] 部分在 setup.cfg 文件中

在版本 4.0 中已删除。

[pytest] 部分在 setup.cfg 文件中现在应命名为 [tool:pytest],以避免与其他 distutils 命令冲突。

Metafunc.addcall

在版本 4.0 中已删除。

Metafunc.addcall 是当前参数化机制的前身。用户应使用 pytest.Metafunc.parametrize()

示例

def pytest_generate_tests(metafunc):
    metafunc.addcall({"i": 1}, id="1")
    metafunc.addcall({"i": 2}, id="2")

变为

def pytest_generate_tests(metafunc):
    metafunc.parametrize("i", [1, 2], ids=["1", "2"])

cached_setup

在版本 4.0 中已删除。

request.cached_setup 是固定装置可用的设置/拆除机制的前身。

示例

@pytest.fixture
def db_session():
    return request.cached_setup(
        setup=Session.create, teardown=lambda session: session.close(), scope="module"
    )

应更新此项以使用标准固定装置机制

@pytest.fixture(scope="module")
def db_session():
    session = Session.create()
    yield session
    session.close()

有关更多信息,可以参阅 文档中的 funcarg 比较部分

非顶级 conftest 文件中的 pytest_plugins

在版本 4.0 中已删除。

现在不推荐在非顶级 conftest.py 文件中定义 pytest_plugins,因为它们将全局激活引用的插件,这很奇怪,因为对于所有其他 pytest 功能,conftest.py 文件仅对位于其下方或与之同级的测试有效

Config.warnNode.warn

在版本 4.0 中已删除。

这些方法是内部 pytest 警告系统的一部分,但自 3.8 以来,pytest 已将其自己的警告使用内置警告系统,因此这两个函数现在已弃用。

Config.warn 应替换为调用标准 warnings.warn,示例

config.warn("C1", "some warning")

变为

warnings.warn(pytest.PytestWarning("some warning"))

Node.warn 现在支持两个签名

  • node.warn(PytestWarning("some message")):现在是调用此函数的推荐方式。警告实例必须是 PytestWarning 或其子类。

  • node.warn("CI", "some message"):此代码/消息格式已删除,应转换为上述警告实例格式。

record_xml_property

在版本 4.0 中已删除。

现在弃用 record_xml_property 固定装置,转而使用更通用的 record_property,其他使用者(例如 pytest-html)可以使用它来获取关于测试运行的自定义信息。

这只是重命名固定装置,因为 API 是相同的

def test_foo(record_xml_property): ...

更改为

def test_foo(record_property): ...

将命令行字符串传递给 pytest.main()

在版本 4.0 中已删除。

将命令行字符串传递给 pytest.main() 已弃用

pytest.main("-v -s")

改为传递一个列表

pytest.main(["-v", "-s"])

通过传递字符串,用户希望 pytest 使用他们正在使用的 shell 规则来解释该命令行(例如 bashPowershell),但以可移植的方式执行此操作非常困难/不可能。

直接调用固定装置

在版本 4.0 中已删除。

直接调用固定装置函数(而不是在测试函数中请求它们)已弃用。

例如

@pytest.fixture
def cell():
    return ...


@pytest.fixture
def full_cell():
    cell = cell()
    cell.make_full()
    return cell

对于新用户来说,这是一个很大的困惑来源,他们通常会交替调用固定装置函数并从测试函数中请求它们,这会破坏固定装置解析模型。

在这些情况下,只需在依赖固定装置中直接请求函数

@pytest.fixture
def cell():
    return ...


@pytest.fixture
def full_cell(cell):
    cell.make_full()
    return cell

或者,如果在测试中多次调用固定装置函数(使其难以应用上述模式)或如果要对代码进行最小的更改,则可以创建一个固定装置,该固定装置使用 name 参数调用原始函数

def cell():
    return ...


@pytest.fixture(name="cell")
def cell_fixture():
    return cell()

yield 测试

在版本 4.0 中已删除。

pytest 支持 yield 样式测试,其中测试函数实际上 yield 函数和值,然后将这些函数和值转换为适当的测试方法。示例

def check(x, y):
    assert x**x == y


def test_squared():
    yield check, 2, 4
    yield check, 3, 9

这将导致生成两个实际测试函数。

这种形式的测试函数不能正确支持固定装置,用户应切换到 pytest.mark.parametrize

@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared(x, y):
    assert x**x == y

通过 Node 访问的内部类

在版本 4.0 中已删除。

现在通过 Node 实例访问 ModuleFunctionClassInstanceFileItem 会发出此警告

usage of Function.Module is deprecated, please use pytest.Module instead

用户只需 import pytest 并使用 pytest 模块访问这些对象。

这已被记录为已弃用多年,但现在我们才真正发出弃用警告。

Node.get_marker

在版本 4.0 中已删除。

作为大型 标记重构和迭代 的一部分,_pytest.nodes.Node.get_marker 已移除。请参阅 文档,了解如何更新代码的提示。

somefunction.markname

在版本 4.0 中已删除。

作为大型 标记重构和迭代 的一部分,我们已弃用使用 MarkInfo,获取元素标记的唯一正确方法是通过 node.iter_markers(name)

pytest_namespace

在版本 4.0 中已删除。

此挂钩已弃用,因为它极大地复杂化了 pytest 内部关于配置和初始化的内容,使得一些错误修复和重构变得不可能。

用法示例

class MySymbol: ...


def pytest_namespace():
    return {"my_symbol": MySymbol()}

依赖此挂钩的插件作者应要求用户直接导入插件模块(使用适当的公共 API)。

作为权宜之计,插件作者仍可以在 pytest_configure 期间将他们的名称注入到 pytest 的命名空间中。

import pytest


def pytest_configure():
    pytest.my_symbol = MySymbol()