Pytest精通指南(17)利用xfail标记用例失败

46 篇文章 1 订阅
32 篇文章 2 订阅
本文详细介绍了pytest框架中的xfail装饰器及其用法,包括标记测试、指定条件、失败原因、运行控制、期望异常和strict参数的含义,帮助开发者更好地管理预期失败的测试用例。
摘要由CSDN通过智能技术生成


请添加图片描述

前言

pytest测试框架中,xfail是一个重要的标记,用于明确标识那些预期会失败的测试用例。

这不是表示测试编写有误或测试框架有问题,而是表示在特定条件下,我们预期这些测试会失败。

当我们使用xfail标记一个测试时,pytest将这样处理:

  • 如果测试确实失败了,它会被认为是预期失败(xfail),并且会在测试报告中标记为成功。
  • 如果测试意外成功了,它会被认为是预期通过(xpass),这通常是一个警告信号,表明预期失败的原因可能已经不存在,或者测试本身的实现可能有问题。

应用场景

使用xfail标记的预期失败场景可能包括:

  • 尚未完成的功能或修复。
  • 在某些平台或环境上已知的问题。
  • 依赖于外部资源或服务的测试,当这些资源或服务暂时不可用时。
  • 尚未实现或尚未完成的测试逻辑。

通过明确标记这些预期失败的测试,pytest帮助开发者更好地了解测试套件的状态,避免误报,并允许他们更专注于解决真正的问题。

xfail 源码分析

这段代码是pytest框架内部的一部分,用于处理xfail(预期失败)标记。

_XfailMarkDecorator类继承自MarkDecorator,是专门用来处理xfail标记的装饰器。

  • 第一个__call__方法接受一个Markable类型的参数arg,并返回一个Markable类型的对象。这里Markable可能是一个协议(Protocol),定义了可以被标记的对象应有的接口。这个方法可能是用于直接标记一个测试函数或方法。
  • 第二个__call__方法接受多个参数,包括condition*conditionsreasonrunraisesstrict,并返回一个MarkDecorator类型的对象。这个方法提供了更灵活的标记选项,允许用户指定多个条件、失败的原因、是否运行测试、预期抛出的异常类型以及是否严格等。

参数解释:

  • condition\*conditions:用于指定标记的条件,可以是字符串或布尔值。多个条件可以通过*conditions传递。
  • reason:一个字符串,解释为什么测试预期会失败。
  • run:一个布尔值,指定是否应该运行这个测试。如果设置为False,则测试将被跳过。
  • raises:一个异常类型或异常类型的元组,指定测试应该引发的异常。如果测试引发了其他异常或没有引发异常,则测试将失败。
  • strict:一个布尔值,如果设置为True,则只有当测试确实失败时,才会将其视为xfail。如果测试成功,则会被视为真正的失败。

总结:

  • _XfailMarkDecorator类的源码定义了如何使用xfail标记来标记预期会失败的测试。
  • 通过重载__call__方法并提供灵活的参数选项,我们可以方便地给测试函数或方法添加xfail标记,并指定相关的条件和信息。
  • 这些标记信息将被pytest框架用于运行时的测试和报告生成。
class _XfailMarkDecorator(MarkDecorator):
    @overload  # type: ignore[override,misc,no-overload-impl]
    def __call__(self, arg: Markable) -> Markable:
        ...

    @overload
    def __call__(
        self,
        condition: Union[str, bool] = False,
        *conditions: Union[str, bool],
        reason: str = ...,
        run: bool = ...,
        raises: Union[
            None, Type[BaseException], Tuple[Type[BaseException], ...]
        ] = ...,
        strict: bool = ...,
    ) -> MarkDecorator:
        ...

xfail 装饰方法

示例代码

import pytest


@pytest.mark.xfail
def test_case_01():
    print("进入test_case_01函数")
    assert 1 == 1

执行结果

请添加图片描述

xfail 装饰类

示例代码

import pytest


@pytest.mark.xfail
class TestClassDemo2:

    def test_case_01(self):
        print("进入test_case_01函数")
        assert 1 == 1

    def test_case_02(self):
        print("进入test_case_02函数")
        assert 1 == 2

执行结果

请添加图片描述

xfail 装饰模块

示例代码

import pytest

pytestmark = pytest.mark.xfail(reason="当前环境或其他原因没法测试")


def test_case():
    print("进入test_case函数")
    assert 1 == 1


class TestClassDemo2:

    def test_case_01(self):
        print("进入test_case_01函数")
        assert 1 == 1

    def test_case_02(self):
        print("进入test_case_02函数")
        assert 1 == 2

执行结果

请添加图片描述

xfail的run参数讲解

官方描述:

  • 如果runTrue,则即使测试被标记为xfail,它仍然会被执行。这允许你查看测试的运行情况,即使你知道它会失败。
  • 如果runFalse,则测试不会被执行。这在你想要跳过某些测试,但又不想将它们完全从测试套件中移除时很有用。

简而言之:

  • run=True(默认值):测试会被执行,即使它被标记为xfail
  • run=False:测试不会被执行。

示例代码

import sys

import pytest


@pytest.mark.xfail(condition=sys.platform == "darwin", reason="Mac系统无法执行")
def test_case():
    print("进入test_case函数")
    assert 1 == 1


@pytest.mark.xfail(condition=True, run=False, reason="Mac系统无法执行")
class TestClassDemo2:
    print("进入类的内部")

    def test_case_01(self):
        print("进入test_case_01函数")
        assert 1 == 1

    def test_case_02(self):
        print("进入test_case_02函数")
        assert 1 == 2

执行结果

请添加图片描述

xfail的raises参数讲解

示例代码

raises:抛出某类型异常,和用例中raise的异常类型一样,结果就是FAILED,否则结果是XFAIL

import pytest


@pytest.mark.xfail
def test_case_01():
    print("进入test_case_01函数")
    assert 1 == 1


@pytest.mark.xfail
def test_case_02():
    print("进入test_case_02函数")
    assert 1 == 1
    raise Exception("手动抛出异常")


@pytest.mark.xfail(raises=RuntimeError, reason="预期抛出RuntimeError异常")
def test_case_03():
    print("进入test_case_03函数")
    assert 1 == 1
    raise RuntimeError("运行时异常")


@pytest.mark.xfail(raises=RuntimeError, reason="预期抛出RuntimeError异常,但实际没有异常")
def test_case_04():
    print("进入test_case_04函数")
    assert 1 == 1


@pytest.mark.xfail(raises=RuntimeError, reason="预期抛出RuntimeError异常,但实际不是")
def test_case_05():
    print("进入test_case_05函数")
    assert 1 == 1
    raise TypeError("随便抛出个异常")


执行结果

请添加图片描述

xfail的strict参数讲解

官方描述:

  • 如果strictFalse(默认值),即使xfail标记的测试用例通过了断言(即测试用例预期失败但实际上成功了),该测试仍然会被标记为XPASS(意外的通过)。如果测试用例未能通过断言(即测试用例预期失败并且实际也失败了),则会被标记为XFAIL(预期的失败)。
  • 如果strictTrue,则xfail标记的测试用例在通过断言时会被视为FAILED(执行失败),因为这违反了预期失败的行为。如果测试未能通过断言,它仍然会被标记为XFAIL(预期的失败)。

简而言之:

  • strict=False(默认):
  • 测试通过断言:XPASS(意外的通过)
  • 测试未通过断言:XFAIL(预期的失败)
  • strict=True
  • 测试通过断言:FAILED(失败)
  • 测试未通过断言:XFAIL(预期的失败)

示例代码

import pytest


@pytest.mark.xfail
def test_case_01():
    print("进入test_case_01函数")
    assert 1 == 1


@pytest.mark.xfail
def test_case_02():
    print("进入test_case_02函数")
    assert 1 == 2


@pytest.mark.xfail(strict=True, reason="如果断言成功,则标记测试用例为执行失败")
def test_case_03():
    print("进入test_case_03函数")
    assert 1 == 1


@pytest.mark.xfail(strict=True, reason="如果断言失败,则标记测试用例为预期失败")
def test_case_04():
    print("进入test_case_04函数")
    assert 1 == 2


@pytest.mark.xfail(strict=False, reason="如果断言成功,则标记测试用例为预期通过")
def test_case_05():
    print("进入test_case_05函数")
    assert 1 == 1


@pytest.mark.xfail(strict=False, reason="如果断言失败,则标记测试用例为预期失败")
def test_case_06():
    print("进入test_case_06函数")
    assert 1 == 2

执行结果

请添加图片描述

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要休息的KK.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值