pytest

框架

pytest-dev/pytest

Python 测试框架,支持从小测试到复杂功能测试。

项目简介

pytest 是一个成熟的全功能 Python 测试工具,支持 fixture 参数化、丰富的插件架构和自动测试发现。提供详细的断言失败信息,方便调试。

README 预览

.. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg\n   :target: https://docs.pytest.org/en/stable/\n   :align: center\n   :height: 200\n   :alt: pytest\n\n\n------\n\n.. image:: https://img.shields.io/pypi/v/pytest.svg\n    :target: https://pypi.org/project/pytest/\n\n.. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg\n    :target: https://anaconda.org/conda-forge/pytest\n\n.. image:: https://img.shields.io/pypi/pyversions/pytest.svg\n    :target: https://pypi.org/project/pytest/\n\n.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/main/graph/badge.svg\n    :target: https://codecov.io/gh/pytest-dev/pytest\n    :alt: Code coverage Status\n\n.. image:: https://github.com/pytest-dev/pytest/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Atest\n\n.. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg\n   :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main\n   :alt: pre-commit.ci status\n\n.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg\n    :target: https://www.codetriage.com/pytest-dev/pytest\n\n.. image:: https://readthedocs.org/projects/pytest/badge/?version=latest\n    :target: https://pytest.readthedocs.io/en/latest/?badge=latest\n    :alt: Documentation Status\n\n.. image:: https://img.shields.io/badge/Discord-pytest--dev-blue\n    :target: https://discord.com/invite/pytest-dev\n    :alt: Discord\n\n.. image:: https://img.shields.io/badge/Libera%20chat-%23pytest-orange\n    :target: https://web.libera.chat/#pytest\n    :alt: Libera chat\n\n\nThe ``pytest`` framework makes it easy to write small tests, yet\nscales to support complex functional testing for applications and libraries.\n\nAn example of a simple test:\n\n.. code-block:: python\n\n    # content of test_sample.py\n    def inc(x):\n        return x + 1\n\n\n    def test_answer():\n        assert inc(3) == 5

常见问题 (5)

故障排除
如何修复 Sphinx 文档构建因 "py:class reference target not found: pluggy._compat.DistFacade" 警告而失败的问题?

此错误发生在使用 Pluggy 1.7.0 构建文档时(例如为 pytest 运行 tox -e docs),因为其 PluginManager.list_plugin_distinfo 的文档字符串引用了私有的、未文档化的类 pluggy._compat.DistFacade,而 -W 会将警告转变为失败。修复方法:在你的 Sphinx conf.py 中将该私有类添加到 nitpick_ignore:

nitpick_ignore = [
    # ... 现有条目 ...
    ("py:class", "pluggy._compat.DistFacade"),
]

这样可以在不锁定或降级 Pluggy 的情况下,对所有其他目标保持严格的引用检查。注意:降级到 Pluggy 1.6.0 并不是有效的变通方案,因为它会触发其他私有 Pluggy 类型引用的警告。

来源 Issue #15190
故障排除
如何修复在比较嵌套序列时出现的 pytest.approx() AttributeError: 'tuple' object has no attribute 'expected' 错误?

pytest.approx() 不支持嵌套数据结构,例如元组列表(如 pytest.approx([(2.0, 2.0)]))。在 pytest <= 9.1.1 中,这会在断言报告期间产生令人困惑的 AttributeError: 'tuple' object has no attribute 'expected'。

解决方法:
1. 在比较前将结构展平:assert [x for t in sut() for x in t] == pytest.approx([2.0, 2.0])
2. 逐个比较元素:result = sut(); assert result[0] == pytest.approx((2.0, 2.0))(单个扁平的数字元组/列表是支持的)
3. 对于数值二维数据,使用 numpy 数组,approx 可以处理。

升级到 pytest 9.2+(来自 PR #14934 的修复)并不会让嵌套结构可用,但会将晦涩难懂的 AttributeError 替换为清晰的错误信息:TypeError: pytest.approx() does not support nested data structures。你仍然必须按照上述方法重构比较。

来源 Issue #12839
故障排除
如何修复 pytest exconly(tryshort=True) 无法移除 'AssertionError: ' 的问题?

这是 pytest 8.0.2 及相关版本中的一个 bug:ExceptionInfo.for_later() 在异常被捕获之前就创建了 ExceptionInfo,并且从未填充其断言 striptext,因此 exconly(tryshort=True) 会保留 AssertionError: 前缀。

直接使用异常值:

with pytest.raises(AssertionError) as exc_info:
    raise AssertionError("message")

message = str(exc_info.value)
assert message == "message"

如果需要保留 exconly() 的行为,可以从捕获的异常重新构造 ExceptionInfo:

from pytest import ExceptionInfo

message = ExceptionInfo.from_exception(
    exc_info.value
).exconly(tryshort=True)

一个适用于 Python 3.9+ 的字符串解决方法是:

message = str(exc_info.value).removeprefix("AssertionError: ")

来源 Issue #12175
故障排除
为什么 pytest 收集了一个测试类,却在它继承 ABCMeta 抽象方法时报告没有测试?

在 pytest 8.3+ 中,抽象测试类会在收集期间被跳过。你的 TestFoo 类仍然是抽象的,因为它没有实现继承而来的 test_foo 方法,所以 pytest 会静默地从中收集不到任何内容。

验证未实现的抽象方法:

python -c "import your_test_module; print(your_test_module.TestFoo.__abstractmethods__)"

这应该会打印 {'test_foo'}。通过在具体测试类中实现每个抽象方法来修复此问题:

class TestFoo(AbstractTestFoo):
    def test_foo(self):
        assert True

然后再次运行 pytest。如果该类是有意设计为抽象的,或者不应被收集,请将其重命名为不以 Test 开头的名称,或者设置 __test__ = False。关于被静默跳过的抽象类的 pytest 警告,此前一直在 issue #13546 和草案 PR #15082 中跟踪。

来源 Issue #15080
故障排除
为什么当我的测试类继承了抽象方法时,pytest 会报告 'collected 0 items'?

TestFoo 仍然是抽象类,因为它继承了 test_foo 却没有实现它。Pytest 在收集阶段会跳过抽象类,因此不会收集到任何测试实例或测试方法。请在具体子类中实现该抽象方法:

class TestFoo(AbstractTestFoo):
    def test_foo(self):
        assert True  # your test

使用以下命令验证收集情况:

pytest --collect-only

现在它应该会列出 TestFoo::test_foo。在 pytest 9.1.1 中,这种情况会被静默跳过;在收集阶段报错或发出警告仅是一项提议中的变更。

来源 Issue #15081