一、测试标记类装饰器

1.1 @pytest.mark - 基础标记装饰器

@pytest.mark.标记名称
  • 功能:为测试函数/类添加自定义标记

  • 常用模式:结合 pytest.ini 注册标记

  • 验证命令

    pytest --markers  # 查看所有已注册标记
    
  • 最佳实践

    # pytest.ini 注册标记
    [pytest]
    markers =
        smoke: 核心功能验证
        regression: 完整回归测试
        performance: 性能测试
        api: API接口测试
    
  • 实例

    import pytest
    
    @pytest.mark.smoke
    def test_login():
        """标记为冒烟测试"""
        assert login("admin", "secure_pass") == True
    
    @pytest.mark.regression
    @pytest.mark.slow
    def test_report_generation():
        """多重标记:回归测试+慢速测试"""
        assert generate_report().is_valid()
    

二、控制测试执行的装饰器

2.1 @pytest.mark.skip - 跳过测试

 @pytest.mark.skip(reason="跳过原因描述") # 必填,说明跳过原因 
  • 效果:无条件跳过该测试

  • 示例

    @pytest.mark.skip(reason="等待API V3发布")
    def test_new_api_feature():
        ...
    

2.2 @pytest.mark.skipif - 条件跳过

@pytest.mark.skipif(
    condition,           # 必填,跳过条件(布尔表达式)
    reason="描述"        # 必填,条件成立时的跳过原因
)
  • 参数说明

    • condition:跳过条件,如 sys.version_info < (3, 8)
    • reason:跳过解释
  • 示例

    @pytest.mark.skipif(
        not HAS_GPU,
        reason="需要GPU加速支持"
    )
    def test_gpu_acceleration():
        ...
    

2.3 @pytest.mark.xfail - 预期失败

@pytest.mark.xfail(
    condition=None,      # 预期失败的条件
    reason=None,         # 原因说明
    strict=False,        # 是否严格模式(默认False)
    raises=None,         # 预期抛出的异常类型
    run=True,            # 是否执行测试(默认执行)
)
  • 参数详解

    参数 类型 默认值 说明
    condition bool None 预期失败条件
    reason str None 失败原因说明
    strict bool False 是否严格模式(通过视为失败)
    raises Exception None 预期抛出的异常类型
    run bool True 是否执行测试代码
  • 使用场景

    # 已知BUG场景
    @pytest.mark.xfail(
        reason="BUG-123: 缓存失效问题",
        strict=True
    )
    def test_cache_behavior():
        ...
    
        
    # 严格模式(预期失败但实际通过会报错)
    @pytest.mark.xfail(strict=True, reason="应在此版本修复")
    def test_should_be_fixed():
        assert fixed_function() == "correct"
    

三、参数化相关装饰器

3.1 @pytest.mark.parametrize - 测试参数化

@pytest.mark.parametrize(
    argnames,           # 参数名(字符串或列表)
    argvalues,          # 参数值列表(可迭代对象)
    indirect=False,     # 是否通过fixture传递参数
    ids=None,           # 自定义测试ID(可调用函数或列表)
    scope=None,         # 参数作用域(覆盖fixture作用域)
)
  • 参数详解

    参数 说明 示例
    argnames 参数名称(逗号分隔字符串或列表) “username,password”
    argvalues 参数值列表 [(“user1”, “pass1”), (“user2”, “pass2”)]
    indirect 是否将参数传递给fixture True/False
    ids 自定义测试ID lambda val: f"login_{val[0]}"
    scope 覆盖fixture作用域 “module”
  • 高级用法

    # 嵌套参数化
    @pytest.mark.parametrize("browser", ["chrome", "firefox"])
    @pytest.mark.parametrize("os", ["win", "mac"], ids=lambda os: os.upper())
    def test_cross_browser(browser, os):
        ...
    

四、Fixtures 相关装饰器

4.1 @pytest.fixture - Fixture 定义

@pytest.fixture(
    scope="function",   # 作用域: function/class/module/session
    params=None,        # 参数列表(支持参数化)
    autouse=False,      # 是否自动使用(无需声明)
    ids=None,           # 参数化ID标识(与params配套)
    name=None,          # Fixture别名(默认函数名)
)
  • 参数详解

    参数 类型 默认 说明
    scope str “function” 作用域范围
    params iterable None 参数列表
    autouse bool False 自动应用
    ids list/callable None 参数ID
    name str None 别名
  • 企业级应用

    @pytest.fixture(
        scope="module",
        params=["zh-CN", "en-US", "ja-JP"],
        ids=["中文", "英语", "日语"],
        name="locale"
    )
    def get_locale(request):
        return request.param
    

3.2 @pytest.mark.usefixtures - 应用 Fixture

@pytest.mark.usefixtures(
    *args  # fixture名称列表
)
  • 作用:显式应用fixture到类或模块

  • 示例

    @pytest.mark.usefixtures("database", "cache")
    class TestDataProcessing:
        ...
    

五、执行控制类装饰器

5.1 @pytest.mark.timeout - 超时控制

@pytest.mark.timeout(
    timeout,            # 超时时间(秒)
    method="thread",     # 控制方法: thread/signal
)
  • 参数说明:
    • timeout:超时时间(秒)
    • method:实现方式(线程或信号)
  • 使用注意:Windows 推荐 method="thread"

5.2 @pytest.mark.filterwarnings - 警告过滤

@pytest.mark.filterwarnings(
    "action:message"  # 过滤规则
)
  • 示例

    @pytest.mark.filterwarnings("ignore:deprecated")
    def test_deprecated_api():
        ...
    

六、异步支持装饰器

5.1 @pytest.mark.asyncio - 异步测试

@pytest.mark.asyncio(
    scope="function"    # 作用域: function/class/module
)
  • 依赖pytest-asyncio 插件

  • 示例

    @pytest.mark.asyncio
    async def test_async_api():
        result = await api_call()
        assert result
    

七、自定义标记装饰器

7.1 创建增强型标记

# conftest.py
def priority(level):
    return pytest.mark.priority(level=level)

# 使用
@priority("high")
def test_critical():
    ...

6.2 动态参数标记

def env_specific(env):
    return pytest.mark.parametrize("env", [env], indirect=True)

# 使用
@env_specific("staging")
def test_staging_api(env):
    ...

八、企业级应用参考

8.1 安全测试标记系统

# security_marks.py
def security_test(level="medium", cve=None):
    marks = [pytest.mark.security(level=level)]
    if cve:
        marks.append(pytest.mark.cve(cve))
    return marks

# 使用
@security_test("high", cve="CVE-2023-1234")
def test_patch_verification():
    ...

8.2 CI/CD 环境感知配置

def ci_only():
    return pytest.mark.skipif(
        not os.getenv("CI"),
        reason="只能在CI环境运行"
    )

# 使用
@ci_only()
def test_deployment_flow():
    ...

九、调试与优化技巧

9.1 查看已注册标记

pytest --markers
# 输出:
@pytest.mark.order_processing: 订单处理流程测试

9.2 查看装饰器效果

pytest --collect-only -v
# 输出:
<Function test_critical[high]>

9.3 动态装饰器调试

@pytest.mark.parametrize("data", test_data)
def test_dynamic(data):
    print(f"\n当前参数: {data}")
    if should_skip(data):
        pytest.skip("数据不适用当前环境")

9.4 按标记筛选测试

# 运行所有安全测试
pytest -m security_high

# 排除慢速测试
pytest -m "not slow"

# 组合筛选
pytest -m "security_medium and not slow"

完整装饰器参考:pytest Decorator Documentation

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐