弃用和移除¶
此页面列出了所有当前已弃用或已在过去主要版本中移除的 pytest 功能。目的是向用户清晰地说明某个功能被移除的原因,以及应使用哪些替代方案。
已弃用的功能¶
以下是所有被视为已弃用的 pytest 功能的完整列表。使用这些功能将发出 PytestWarning 或其子类,可以使用 标准警告过滤器 进行过滤。
monkeypatch.syspath_prepend 与传统命名空间包¶
自 9.0 版本弃用。
当使用 monkeypatch.syspath_prepend() 时,如果导入了 pkg_resources,pytest 会自动调用 pkg_resources.fixup_namespace_packages()。这仅适用于使用 pkg_resources.declare_namespace() 的传统命名空间包。
传统命名空间包已弃用,取而代之的是原生命名空间包(PEP 420)。如果您在 __init__.py 文件中使用 pkg_resources.declare_namespace(),您应该通过从命名空间包中移除 __init__.py 文件来迁移到原生命名空间包。
此弃用警告仅在以下情况发出:
pkg_resources已导入,并且被预置的特定路径包含一个已声明的命名空间包(通过
pkg_resources.declare_namespace())。
要解决此警告,请将您的传统命名空间包转换为原生命名空间包
传统命名空间包(已弃用)
# mypkg/__init__.py
__import__("pkg_resources").declare_namespace(__name__)
原生命名空间包(推荐)
只需完全移除 __init__.py 文件即可。Python 3.3+ 原生支持不带 __init__.py 的命名空间包。
依赖于异步 fixture 的同步测试¶
自 8.4 版本弃用。
长期以来,pytest 在遇到异步测试函数时会报错,提示用户安装一个可以处理它的插件。但是,如果有一个异步 fixture 被同步测试所依赖,则不会报错。如果 fixture 是一个异步函数,你会收到“未等待的协程”警告,但对于异步 yield fixture,你甚至不会收到。即使你安装了处理异步测试的插件,这也是一个问题,因为它们可能需要特殊的装饰器来处理异步 fixture,并且有些可能无法健壮地处理用户意外地从同步测试请求异步 fixture 的情况。fixture 值被缓存会使这更加难以理解,如果 fixture 首先被异步测试请求,然后被同步测试请求,一切都将“正常工作”。
不幸的是,没有 100% 可靠的方法来识别用户何时犯了错误,或者何时他们期望从 fixture 中获得一个未等待的对象,并由他们自己处理。要在确实打算处理这种情况时抑制此警告,您可以将异步 fixture 包装在同步 fixture 中
import asyncio
import pytest
@pytest.fixture
async def unawaited_fixture():
return 1
def test_foo(unawaited_fixture):
assert 1 == asyncio.run(unawaited_fixture)
应更改为
import asyncio
import pytest
@pytest.fixture
def unawaited_fixture():
async def inner_fixture():
return 1
return inner_fixture()
def test_foo(unawaited_fixture):
assert 1 == asyncio.run(unawaited_fixture)
您还可以利用 pytest_fixture_setup 在 pytest 看到协程/异步生成器之前处理它们——这是当前异步 pytest 插件的处理方式。
如果用户在 conftest.py 中或在包含同步测试和 fixture 的文件中有一个带有 autouse=True 的异步 fixture,他们将收到此警告。除非您正在使用专门处理带有同步测试的异步 fixture 的插件,否则我们强烈建议不要采用这种做法。这可能导致不可预测的行为(对于更大的作用域,如果异步测试首先请求 fixture,由于值缓存,它可能看起来“正常工作”),并会生成未等待协程的运行时警告(但仅适用于非 yield fixture)。此外,它会给其他开发人员造成歧义,即 fixture 是否旨在为同步测试执行设置。
anyio pytest 插件支持带有异步 fixture 的同步测试,但存在某些限制。
pytest.importorskip 关于 ImportError 的默认行为¶
自 8.2 版本弃用。
传统上,pytest.importorskip() 会捕获 ImportError,最初的目的是跳过那些依赖模块未安装的测试,例如使用不同依赖项进行测试。
然而,有些包可能已安装在系统中,但由于其他问题(例如编译错误或损坏的安装)而无法导入。在这种情况下,pytest.importorskip() 仍然会静默跳过测试,但通常用户更希望看到意外错误,以便解决底层问题。
在 8.2 中,添加了 exc_type 参数,允许用户传递 ModuleNotFoundError,仅当模块确实找不到时才跳过测试,而不是因为其他错误。
默认情况下只捕获 ModuleNotFoundError(并让其他错误传播)将是最佳解决方案,但为了向后兼容,pytest 将保留现有行为,但如果出现以下情况,将引发警告:
捕获的异常类型为
ImportError,并且用户未显式传递
exc_type。
如果导入尝试引发 ModuleNotFoundError(常见情况),则跳过模块且不发出警告。
这样,常见情况将保持相同的运行方式,而意外错误现在将发出警告,用户可以通过显式传递 exc_type=ImportError 来抑制警告。
在 9.0 中,警告将变为错误,在 9.1 中,pytest.importorskip() 将默认仅捕获 ModuleNotFoundError,并且不再发出警告——但用户仍然可以通过将其传递给 exc_type 来捕获 ImportError。
Node 构造函数中的 fspath 参数被 pathlib.Path 替换¶
自 7.0 版本弃用。
为了支持从 py.path.local 到 pathlib 的过渡,Node 构造函数(如 pytest.Function.from_parent() 和 pytest.Class.from_parent())的 fspath 参数现已弃用。
构建节点的插件应传递 pathlib.Path 类型的 path 参数,而不是 fspath 参数。
鼓励实现自定义项和收集器的插件将 fspath 参数(py.path.local)替换为 path 参数(pathlib.Path),并尽可能放弃 py 库的其他用法。
如果可能,带有自定义项的插件应使用 协作构造函数 以避免硬编码它们仅传递给超类的参数。
注意
Node 参数和属性的名称(新属性为 path)与钩子的情况 相反,如下所述(旧参数为 path)。
这是由于历史原因造成的不幸遗留问题,随着我们逐渐摆脱 py 依赖(请参阅 #9283 了解更长的讨论),该问题应在未来的版本中解决。
由于像 reportinfo() 这样的方法仍在迁移中,仍然期望返回 py.path.local 对象,因此节点仍然具有 fspath (py.path.local) 和 path (pathlib.Path) 属性,无论构造函数中使用了哪个参数。我们预计在未来的版本中弃用 fspath 属性。
使用标记配置钩子规范/实现¶
在 pluggy,即 pytest 的插件库,成为独立的包并拥有清晰的 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 属性
tryfirsttrylastoptionalhookhookwrapper
更改了 hookwrapper 属性
firstresulthistoric
钩子参数 py.path.local 被 pathlib.Path 替换¶
自 7.0 版本弃用。
为了支持从 py.path.local 到 pathlib 的过渡,以下钩子现在接收额外的参数
pytest_ignore_collect(collection_path: pathlib.Path)等同于pathpytest_pycollect_makemodule(module_path: pathlib.Path)等同于pathpytest_report_header(start_path: pathlib.Path)等同于startdirpytest_report_collectionfinish(start_path: pathlib.Path)等同于startdir
伴随的基于 py.path.local 的路径已被弃用:手动调用这些钩子的插件应只传递新的 pathlib.Path 参数,用户应更改其钩子实现以使用新的 pathlib.Path 参数。
直接构造内部类¶
自 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.Collector 和 pytest.Item 之间的菱形继承¶
自 7.0 版本弃用。
定义一个既是 Item 又是 Collector(例如 File)的自定义 pytest 节点类型现在会发出警告。这从未得到合理支持,并会触发难以调试的错误。
一些提供 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 在遇到此问题时会发出警告,并在未来的版本中引发错误。
yield_fixture 函数/装饰器¶
自 6.2 版本弃用。
pytest.yield_fixture 是 pytest.fixture() 的弃用别名。
它已经弃用很长时间了,所以可以安全地进行搜索/替换。
移除的功能和破坏性更改¶
如我们的 向后兼容性政策 所述,弃用功能只会在经过适当的弃用期后在主要版本中移除。
一些无法弃用的破坏性更改也已列出。
yield 测试¶
在 4.0 版本中移除: yield 测试 xfail。
在 8.4 版本中移除: yield 测试引发收集错误。
pytest 不再支持 yield 风格的测试,其中测试函数实际上 yield 函数和值,然后将其转换为适当的测试方法。例如
def check(x, y):
assert x**x == y
def test_squared():
yield check, 2, 4
yield check, 3, 9
这将导致生成两个实际的测试函数。
这种形式的测试函数不支持 fixture,用户应该切换到 pytest.mark.parametrize
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared(x, y):
assert x**x == y
支持为 nose 编写的测试¶
自 7.2 版本弃用。
在 8.0 版本中移除。
对运行为 nose 编写的测试的支持现已弃用。
nose 多年来一直处于维护模式,并且维护该插件并非易事,因为它会蔓延到整个代码库(有关更多详细信息,请参阅 #9886)。
setup/teardown¶
可能让用户感到惊讶的一点是,普通的 setup 和 teardown 方法不是 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_method 和 teardown_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 样式。一种方法是使用 fixture
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 不再遵守此属性。
将 msg= 传递给 pytest.skip、pytest.fail 或 pytest.exit¶
自 7.0 版本弃用。
在 8.0 版本中移除。
将关键字参数 msg 传递给 pytest.skip()、pytest.fail() 或 pytest.exit() 现已弃用,应改用 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 版本弃用。
在 9.0 版本中更改。
--strict 命令行选项已被弃用,取而代之的是 --strict-markers,它更好地表达了该选项的作用。
在 8.1 版本中,我们意外地取消了对 --strict 的弃用。
在 9.0 版本中,我们更改了 --strict,使其设置新的 strict 配置选项。它现在启用所有与严格性相关的选项(包括 strict_markers)。
实现 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.Module 或 pytest.File¶
在 8.0 版本中更改。
Package 收集器节点指定一个 Python 包,即一个包含 __init__.py 文件的目录。以前 Package 是 pytest.Module 的子类型(表示一个 Python 模块),该模块是 __init__.py 文件。这已被认为是一个设计错误(详见 #11137 和 #7777)。
Package 节点的 path 属性现在指向包目录而不是 __init__.py 文件。
请注意,__init__.py 的 Module 节点(它不是 Package)仍然可能存在,如果在收集期间被拾取(例如,如果您将 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 命令行选项,允许指定在测试失败时如何显示捕获的输出:no、stdout、stderr、log 或 all(默认)。
结果日志 (--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 版本中更改。
junit_family 选项的默认值在 pytest 6.0 中将更改为 xunit2,这是旧 xunit1 格式的更新,并且现代工具默认支持此文件类型(例如 Jenkins、Azure Pipelines 等)。
建议用户尝试新的 xunit2 格式,看看他们使用 JUnit XML 文件的工具是否支持它。
要使用新格式,请更新您的配置文件
[pytest]
junit_family = "xunit2"
[pytest]
junit_family = xunit2
如果您发现您的工具不支持新格式,并且希望继续使用旧版本,请将选项设置为 legacy
[pytest]
junit_family = "legacy"
[pytest]
junit_family = legacy
通过使用 legacy,您将在升级到 pytest 6.0 时继续使用旧版/xunit1 格式,届时默认格式将是 xunit2。
为了让用户了解此过渡,如果命令行中提供了 --junit-xml 选项,但 junit_family 未在 pytest.ini 中显式配置,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() 已移除 - 请改为使用关键字传递它们。
funcargnames 是 fixturenames 的别名¶
在 6.0 版本中移除。
FixtureRequest、Metafunc 和 Function 类通过 aptly-named fixturenames 属性跟踪其关联 fixture 的名称。
在 pytest 2.3 之前,此属性名为 funcargnames,此后我们一直将其保留为别名。现在它终于要被移除,因为它在我们需要区分 fixture 名称和非 fixture(例如 pytest.mark.parametrize)提供的名称的地方经常引起混淆。
pytest.config 全局对象¶
在 5.0 版本中移除。
pytest.config 全局对象已弃用。请改用 request.config(通过 request fixture),或者如果您是插件作者,请使用 pytest_configure(config) 钩子。请注意,许多钩子也可以间接访问 config 对象,例如通过 session.config 或 item.config。
pytest.raises 的 "message" 参数¶
在 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 版本中移除。
在 Collector 子类中使用名为 "Class" 的对象来自定义收集的节点类型已弃用。用户应改用 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 版本中,fixture 可以使用 pytest_funcarg__ 前缀定义
def pytest_funcarg__data():
return SomeData()
切换到 @pytest.fixture 装饰器
@pytest.fixture
def data():
return SomeData()
setup.cfg 文件中的 [pytest] 部分¶
在 4.0 版本中移除。
setup.cfg 文件中的 [pytest] 部分现在应命名为 [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 是 fixture 可用的 setup/teardown 机制的前身。
示例
@pytest.fixture
def db_session():
return request.cached_setup(
setup=Session.create, teardown=lambda session: session.close(), scope="module"
)
这应该更新以利用标准 fixture 机制
@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.warn 和 Node.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 fixture 现已弃用,取而代之的是更通用的 record_property,后者可供其他消费者(例如 pytest-html)用于获取有关测试运行的自定义信息。
这仅仅是重命名 fixture 的问题,因为 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 规则(例如 bash 或 Powershell)解释该命令行,但这很难/不可能以可移植的方式实现。
直接调用 fixture¶
在 4.0 版本中移除。
直接调用 fixture 函数,而不是在测试函数中请求它们,已弃用。
例如
@pytest.fixture
def cell():
return ...
@pytest.fixture
def full_cell():
cell = cell()
cell.make_full()
return cell
这给新用户带来了很大的困惑,他们经常互换地调用 fixture 函数和从测试函数中请求它们,这破坏了 fixture 解析模型。
在这些情况下,只需在依赖的 fixture 中直接请求函数
@pytest.fixture
def cell():
return ...
@pytest.fixture
def full_cell(cell):
cell.make_full()
return cell
或者,如果 fixture 函数在测试中被多次调用(使其难以应用上述模式)或者如果您想对代码进行最小的更改,您可以创建一个 fixture,它与 name 参数一起调用原始函数
def cell():
return ...
@pytest.fixture(name="cell")
def cell_fixture():
return cell()
通过 Node 访问内部类¶
在 4.0 版本中移除。
通过 Node 实例访问 Module、Function、Class、Instance、File 和 Item 现在会发出此警告
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 的命名空间中注入他们的名称,通常是在 pytest_configure 期间
import pytest
def pytest_configure():
pytest.my_symbol = MySymbol()