Pytest 预期失败测试:如何标记“已知问题”用例

概述

在自动化测试过程中,我们经常会遇到一些已知的问题,比如:

  • 功能尚未修复的 bug
  • 某些边界条件还未处理
  • 第三方服务暂时不可用

虽然这些情况会导致测试失败,但我们并不希望它们影响整体测试结果。Pytest 提供了一个非常实用的功能来应对这种情况 ------ 使用 @pytest.mark.xfail 装饰器 来标记"预期失败"的测试用例。

什么是预期失败

预期失败(Expected Failure) 是指我们明确知道某个测试会失败,但仍然保留该测试,用于监控未来是否"意外变好"或"仍按预期失败"。

与跳过测试(skip)不同的是:

  • skip 表示不执行测试。
  • xfail 表示执行测试,但接受它的失败。

基本使用方式

示例 1:无条件标记为预期失败

python 复制代码
import pytest

@pytest.mark.xfail
def test_known_issue():
    assert 1 == 2  # 明确知道这个会失败

运行结果中显示为 XFAIL(预期失败):

复制代码
XFAIL test_xfail.py::test_known_issue

示例 2:有条件地预期失败

当某些功能只在特定条件下才会失败时,可以结合 reasoncondition 参数使用。

python 复制代码
import pytest
import sys

@pytest.mark.xfail(sys.platform == "win32", reason="Windows 上存在兼容性问题")
def test_platform_specific_issue():
    assert False

如果当前平台是 Windows,则此测试被标记为 XFAIL

示例 3:测试"意外成功"

如果你希望知道某个"预期失败"的测试竟然通过了,可以用 strict=True 参数来将其标记为失败:

python 复制代码
@pytest.mark.xfail(strict=True)
def test_unexpected_success():
    assert True  # 这个测试通过了,但被标记为 xfail,所以整个测试会失败

运行结果:

复制代码
XFAIL test_xfail.py::test_unexpected_success
FAILED test_xfail.py::test_unexpected_success - assert True

注意:strict=True 表示如果测试意外成功,就认为测试失败。

结合参数化使用 xfail

你还可以在参数化测试中对某组参数进行预期失败标记:

python 复制代码
import pytest

@pytest.mark.parametrize("a, b", [
    (2, 3),
    pytest.param(1, 0, marks=pytest.mark.xfail(reason="除数不能为0")),
    (-1, -1)
])
def test_divide(a, b):
    assert a / b > 0

这样 (1, 0) 这一组会被标记为预期失败。

如何查看预期失败的测试

默认情况下,Pytest 会报告所有预期失败的测试,你可以使用 -v 查看详细信息:

bash 复制代码
pytest -v

输出类似如下内容:

复制代码
test_xfail.py::test_known_issue XFAIL (原因:这是一个已知问题)
test_xfail.py::test_platform_specific_issue XFAIL

常见场景

场景 1:标记未修复的 Bug 测试

python 复制代码
@pytest.mark.xfail(reason="BUG #12345 仍未修复")
def test_bug_12345():
    result = buggy_function()
    assert result == expected_value

场景 2:根据模块是否存在做预期失败

python 复制代码
try:
    import some_optional_module
    HAVE_MODULE = True
except ImportError:
    HAVE_MODULE = False

@pytest.mark.xfail(not HAVE_MODULE, reason="依赖模块缺失")
def test_with_optional_dependency():
    some_optional_module.do_something()

注意事项

注意点 说明
xfail 可用于函数、类或参数化测试 灵活控制粒度
不建议长期保留大量 xfail 测试 容易忽略真正需要修复的问题
使用 strict=True 可防止"预期失败"的测试意外通过 有助于及时发现变更
xfail 不等于 skip skip 是跳过不执行;xfail 是执行但接受失败

总结

本文的重点有以下几点:

✅ 什么是预期失败(XFail)

✅ 如何使用 @pytest.mark.xfail 标记测试

✅ 如何根据条件动态标记预期失败

✅ 如何识别"意外成功"的测试

✅ 使用 xfail 的最佳实践和注意事项

合理使用 xfail,不仅能帮助你管理已知问题,还能提升测试的可读性和维护性