废弃和移除¶
本页面列出了所有当前已废弃或在过去主要版本中已移除的 pytest 功能。目的是向用户清晰地说明某个功能被移除的原因,以及应该使用哪些替代方案。
废弃功能¶
下面是所有被视为已废弃的 pytest 功能的完整列表。使用这些功能将发出 PytestWarning
或其子类,可以使用标准警告过滤器进行过滤。
依赖于异步 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
参数现已废弃。
构造节点的插件应该传递 path
参数(类型为 pathlib.Path
),而不是 fspath
参数。
鼓励实现自定义项和收集器的插件将 fspath
参数(py.path.local
)替换为 path
参数(pathlib.Path
),并尽可能删除 py
库的任何其他用法。
如果可能,带有自定义项的插件应使用协作构造函数,以避免硬编码它们只传递给超类的参数。
注意
Node
参数和属性的名称(新属性为 path
)与 hooks 的情况 相反,如下所述(旧参数为 path
)。
这由于历史原因是一个不幸的产物,随着我们慢慢摆脱 py 依赖,这个问题应该在未来版本中得到解决(有关更长的讨论,请参阅 #9283)。
由于 reportinfo()
等方法仍在进行迁移,该方法仍应返回 py.path.local
对象,因此节点仍具有 fspath
(py.path.local
)和 path
(pathlib.Path
)属性,无论构造函数中使用了哪个参数。我们预计在未来版本中废弃 fspath
属性。
使用标记配置 hook spec/impls¶
在 pytest 的插件库 pluggy 成为独立包并拥有清晰的 API 之前,pytest 只是使用 pytest.mark
来配置 hooks。
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
hooks 的 py.path.local
参数被 pathlib.Path
替换¶
自版本 7.0 废弃。
为了支持从 py.path.local
到 pathlib
的转换,以下 hooks 现在接收额外的参数:
pytest_ignore_collect(collection_path: pathlib.Path)
等同于path
pytest_pycollect_makemodule(module_path: pathlib.Path)
等同于path
pytest_report_header(start_path: pathlib.Path)
等同于startdir
pytest_report_collectionfinish(start_path: pathlib.Path)
等同于startdir
相应的基于 py.path.local
的路径已废弃:手动调用这些 hooks 的插件应仅传递新的 pathlib.Path
参数,用户应更改其 hook 实现以使用新的 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
的自定义 pytest 节点类型(例如 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: ...
用户期望在这种情况下,当调用 user
时,usefixtures
标记会产生使用 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_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 不再尊重此属性。
向 pytest.skip
、pytest.fail
或 pytest.exit
传递 msg=
¶
自版本 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 废弃。
在版本 8.0 中移除。
--strict
命令行选项已废弃,取而代之的是 --strict-markers
,它更好地传达了该选项的功能。
我们计划未来可能会重新引入 --strict
,并使其成为所有严格性相关选项的包容性标志(目前是 --strict-markers
和 --strict-config
,未来可能会引入更多)。
实现 pytest_cmdline_preparse
hook¶
自版本 7.0 废弃。
在版本 8.0 中移除。
实现 pytest_cmdline_preparse
hook 已正式废弃。请改为实现 pytest_load_initial_conftests
hook。
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
hook¶
自版本 6.0 废弃。
在版本 7.0 中移除。
此 hook 包含一个 item
参数,该参数无法通过 pytest-xdist
序列化。
请改用 pytest_warning_recorded
hook,它将 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
hook¶
在版本 6.0 中移除。
pytest_collect_directory
hook 多年来一直无法正常工作(它被调用但结果被忽略)。用户可以考虑改用 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.ini
:
[pytest]
junit_family=xunit2
如果您发现您的工具不支持新格式,并且希望继续使用旧版本,请将该选项设置为 legacy
:
[pytest]
junit_family=legacy
通过使用 legacy
,当升级到 pytest 6.0 时,您将继续使用 legacy/xunit1 格式,其中默认格式将是 xunit2
。
为了让用户了解过渡,如果命令行中给出了 --junit-xml
选项,但未在 pytest.ini
中显式配置 junit_family
,pytest 将发出警告。
已知支持 xunit2
格式的服务
节点构造更改为 Node.from_parent
¶
在版本 6.0 中更改。
现在节点的构造应使用命名构造函数 from_parent
。这种 API 表面限制旨在更好地/更简单地重构收集树。
这意味着以前使用 MyItem(name="foo", parent=collector, obj=42)
的方式,现在必须调用 MyItem.from_parent(collector, name="foo")
。
希望支持旧版本 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
类通过其恰当命名的 fixturenames
属性跟踪其关联 fixture 的名称。
在 pytest 2.3 之前,此属性名为 funcargnames
,自那时起我们一直将其保留为别名。现在它终于要被移除,因为它在我们需要或插件作者必须区分 fixture 名称和非 fixture(例如 pytest.mark.parametrize
)提供的名称时常常引起混淆。
pytest.config
全局对象¶
在版本 5.0 中移除。
pytest.config
全局对象已废弃。请改用 request.config
(通过 request
fixture)或如果你是插件作者,请使用 pytest_configure(config)
hook。请注意,许多 hook 也可以通过 session.config
或 item.config
等间接访问 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 中移除。
此 hook 已废弃,因为它极大地复杂了 pytest 内部关于配置和初始化的机制,使得一些错误修复和重构变得不可能。
用法示例:
class MySymbol: ...
def pytest_namespace():
return {"my_symbol": MySymbol()}
依赖此 hook 的插件作者应改为要求用户现在直接导入插件模块(具有适当的公共 API)。
作为权宜之计,插件作者仍可在 pytest 的命名空间中注入其名称,通常在 pytest_configure
期间:
import pytest
def pytest_configure():
pytest.my_symbol = MySymbol()