目录
1、@pytest.mark.parametrize:2、@pytest.mark.skip和@pytest.mark.skipif:3、@pytest.mark.xfail和@pytest.mark.xfailif:4、@pytest.mark.tryfirst和@pytest.mark.trylast:5、@pytest.mark.usefixtures:6、@pytest.mark.filterwarnings:7、@pytest.mark.timeout(通过 pytest-timeout 插件提供):8、@pytest.mark.flaky(通过 pytest-flaky 插件提供):9、@pytest.mark.order(通过 pytest-order 插件提供):10、自定义标记:前言:在 pytest 测试框架中,注解(通常称为装饰器)用于为测试函数、类或方法提供额外的信息或元数据。这些装饰器可以影响测试的执行方式、报告方式以及测试的组织结构。pytest 提供了多种内置的装饰器,以及通过插件扩展的额外装饰器
以下是一些常用的 pytest 装饰器及其用途:
1、@pytest.mark.parametrize:
用于参数化测试,允许您为测试函数提供多个参数集,pytest 将为每个参数集运行一次测试。示例:@pytest.mark.parametrize("input,expected", [(1, 2), (3, 4)])
import pytest @pytest.mark.parametrize("input,expected", [(1, 2), (3, 4), (5, 6)])def test_addition(input, expected): assert input + 1 == expected
在这个例子中,test_addition
函数将使用三组不同的参数((1, 2)
,(3, 4)
,(5, 6)
)分别运行三次。
2、@pytest.mark.skip和@pytest.mark.skipif:
用于跳过测试。@pytest.mark.skip
无条件跳过测试,而@pytest.mark.skipif
根据条件跳过测试。示例:@pytest.mark.skip(reason="Not ready yet")
或@pytest.mark.skipif(sys.version_info < (3, 6), reason="Python 3.6+ required")
import pytestimport sys# 无条件跳过@pytest.mark.skip(reason="This test is not ready yet")def test_not_ready(): assert True# 根据条件跳过@pytest.mark.skipif(sys.version_info < (3, 6), reason="Python 3.6+ required")def test_python_version(): assert True
在第一个例子中,test_not_ready
函数将被无条件跳过。在第二个例子中,如果 Python 版本低于 3.6,test_python_version
函数将被跳过。
3、@pytest.mark.xfail和@pytest.mark.xfailif:
用于标记预期失败的测试。这些测试将被执行,但如果它们失败了,则不会被视为错误。示例:@pytest.mark.xfail(reason="Known issue")
或@pytest.mark.xfailif(some_condition, reason="Condition not met")
注意:@pytest.mark.xfailif不是 pytest 内置的,但可以通过类似逻辑实现条件性的 xfail
import pytest# 标记预期失败的测试@pytest.mark.xfail(reason="This is a known issue")def test_xfail(): assert False# 可以通过编写一个函数来模拟 @pytest.mark.xfailif 的行为def pytest_xfail_if(condition, reason): def decorator(func): if condition: func = pytest.mark.xfail(reason=reason)(func) return func return decorator# 使用模拟的 @pytest.mark.xfailif@pytest_xfail_if(True, reason="Condition met, expect failure")def test_conditional_xfail(): assert False
4、@pytest.mark.tryfirst和@pytest.mark.trylast:
用于控制测试的执行顺序,尤其是在有多个钩子函数(如 setup/teardown 方法)时。这些装饰器通常与 pytest 插件中的钩子函数一起使用。通常与 pytest 插件中的钩子函数一起使用
# 假设有一个 pytest 插件提供了 setup 和 teardown 钩子函数# 并且我们想要某个测试在这些钩子函数中首先或最后执行# 注意:这里的示例是假设性的,因为 @pytest.mark.tryfirst 和 @pytest.mark.trylast# 通常不直接用于测试函数,而是用于钩子函数或插件实现# 假设的 setup 和 teardown 钩子函数(实际上需要由 pytest 插件提供)# @pytest.hookimpl(tryfirst=True)# def pytest_setup():# pass# @pytest.hookimpl(trylast=True)# def pytest_teardown():# pass# 假设的测试函数(实际上不会直接使用 @pytest.mark.tryfirst 或 @pytest.mark.trylast)# @pytest.mark.tryfirst # 这通常不会直接用于测试函数def test_tryfirst(): pass# @pytest.mark.trylast # 这通常也不会直接用于测试函数def test_trylast(): pass
5、@pytest.mark.usefixtures:
用于声明测试将使用的 fixture。虽然这不是严格意义上的装饰器(因为它不直接修饰函数),但它用于指定测试依赖的 fixture。示例:@pytest.mark.usefixtures("my_fixture")
import pytest@pytest.fixturedef my_fixture(): return "fixture value"@pytest.mark.usefixtures("my_fixture")def test_with_fixture(my_fixture_value): assert my_fixture_value == "fixture value"# 注意:在实际使用中,pytest 会自动将 fixture 的值注入到测试函数中,# 因此测试函数的参数名应与 fixture 的名称相匹配(或使用 pytest.mark.parametrize 来指定参数名)。# 上面的示例中,为了说明 @pytest.mark.usefixtures 的用法,# 假设了一个名为 my_fixture_value 的参数,但在实际代码中应直接使用 my_fixture。# 正确的用法如下:@pytest.mark.usefixtures("my_fixture")def test_with_fixture_correct(my_fixture): assert my_fixture == "fixture value"
在这个例子中,test_with_fixture_correct
函数将使用名为my_fixture
的 fixture。请注意,在实际代码中,您不需要(也不应该)在测试函数参数中显式地指定 fixture 的值;pytest 会自动将其注入
6、@pytest.mark.filterwarnings:
用于控制测试期间应如何处理警告。示例:@pytest.mark.filterwarnings("ignore::DeprecationWarning")
import pytestimport warnings@pytest.mark.filterwarnings("ignore::DeprecationWarning")def test_with_warnings(): warnings.warn("This is a deprecation warning", DeprecationWarning) assert True
在这个例子中,test_with_warnings
函数将忽略DeprecationWarning
类型的警告。
7、@pytest.mark.timeout(通过 pytest-timeout 插件提供):
用于设置测试的超时时间。如果测试在指定时间内未完成,则将被标记为失败。示例:@pytest.mark.timeout(10)
(10秒超时)import pytest@pytest.mark.timeout(5) # 设置超时时间为5秒def test_with_timeout(): import time time.sleep(10) # 这将触发超时失败 assert True
在这个例子中,test_with_timeout
函数将在5秒后超时失败,因为time.sleep(10)
会使测试运行超过指定的超时时间。
8、@pytest.mark.flaky(通过 pytest-flaky 插件提供):
用于标记可能间歇性失败的测试,并允许它们在一定数量的重试后通过。示例:@pytest.mark.flaky(reruns=3, reruns_delay=2)
(重试3次,每次延迟2秒)import pytest@pytest.mark.flaky(reruns=3, reruns_delay=1) # 设置重试3次,每次延迟1秒def test_flaky(): import random assert random.choice([True, False]) # 这将随机成功或失败
在这个例子中,test_flaky
函数将随机成功或失败。如果它失败了,pytest-flaky 插件将重试它最多3次,每次之间延迟1秒。
9、@pytest.mark.order(通过 pytest-order 插件提供):
用于指定测试的执行顺序。示例:@pytest.mark.order(1)
(数字越小,执行越早)import pytest@pytest.mark.order(1) # 设置执行顺序为1def test_first(): assert True@pytest.mark.order(2) # 设置执行顺序为2def test_second(): assert True
在这个例子中,test_first
函数将先于test_second
函数执行,因为它们的执行顺序被分别设置为1和2。
10、自定义标记:
您可以使用@pytest.mark.<name>
语法创建自定义的标记,并在测试配置文件中定义它们的行为。示例:@pytest.mark.my_custom_mark
(然后在 pytest.ini 或 pytest.mark 文件中定义它)import pytest# 在 pytest.ini 或 pytest.mark 文件中定义自定义标记# [pytest]# markers =# my_custom_mark: This is a custom marker@pytest.mark.my_custom_mark # 使用自定义标记def test_with_custom_mark(): assert True
我们定义了一个名为my_custom_mark
的自定义标记,并在test_with_custom_mark
函数中使用了它。请注意,您需要在 pytest 的配置文件中(如pytest.ini
或pytest.mark
)定义这个自定义标记,以便 pytest 能够识别它。
请注意,上述列表中的一些装饰器(如@pytest.mark.timeout和@pytest.mark.flaky)是通过 pytest 插件提供的,因此在使用它们之前需要确保已安装相应的插件。
在使用这些装饰器时,请确保您了解它们如何影响测试的执行和报告,以及它们是否适用于您的测试场景。