You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pytest测试指定装饰器是否已应用到多个函数上

实现方案

你已经单独完成了装饰器本身的功能测试,现在只需要做绑定校验,不需要为每个端点重复写功能测试,以下是最简便的实现方式:

方案1:给装饰器加专属标识(优先推荐)

首先给你的check_user装饰器加一个自定义属性作为绑定标记,性能最高、逻辑最稳定:

from functools import wraps

def check_user(func):
    """Only allow admins to change the user_id in the annotated function.

    Use as decorator: @check_user
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 原有装饰器逻辑不变
        ...
    # 新增专属标记属性
    wrapper.__check_user_applied = True
    return wrapper

然后编写参数化测试,直接导入所有需要校验的FastAPI端点函数,判断标记是否存在即可:

import pytest
# 导入你所有加了check_user装饰器的端点函数
from your_api_module import foo, bar, gaga, xxx, yyy

@pytest.mark.parametrize("endpoint_func", [
    foo, bar, gaga, xxx, yyy # 把20个端点都列在这里
])
def test_check_user_decorator_bound(endpoint_func):
    assert hasattr(endpoint_func, "__check_user_applied"), f"端点{endpoint_func.__name__}未绑定check_user装饰器"
    assert endpoint_func.__check_user_applied is True

如果存在多层装饰器叠加的情况,可以加一个递归校验的辅助函数,逐层查找被包装的函数:

def has_check_user_decorator(func):
    current_func = func
    while current_func:
        if hasattr(current_func, "__check_user_applied") and current_func.__check_user_applied:
            return True
        # 拿到上一层被包装的原函数
        current_func = getattr(current_func, "__wrapped__", None)
    return False

# 测试用例改成调用辅助函数
@pytest.mark.parametrize("endpoint_func", [foo, bar, gaga,])
def test_check_user_decorator_bound(endpoint_func):
    assert has_check_user_decorator(endpoint_func), f"端点{endpoint_func.__name__}未绑定check_user装饰器"

进阶优化:自动扫描端点无需手动罗列

如果不想每次新增端点都手动更新测试的参数列表,可以直接扫描FastAPI实例的路由自动获取所有端点函数:

import pytest
from your_project.main import app # 导入你的FastAPI实例对象

def get_target_endpoints():
    endpoints = []
    for route in app.routes:
        if not hasattr(route, 'endpoint'):
            continue
        # 可在这里加过滤逻辑,比如只校验路径前缀为/admin的端点
        if route.path.startswith("/admin"):
            endpoints.append(route.endpoint)
    return endpoints

@pytest.mark.parametrize("endpoint_func", get_target_endpoints())
def test_check_user_decorator_bound(endpoint_func):
    assert has_check_user_decorator(endpoint_func), f"端点{endpoint_func.__name__}未绑定check_user装饰器"

方案2:无需修改装饰器的校验方式

如果不方便修改原有装饰器的代码,可以用inspect模块检查闭包信息判断装饰器是否被应用,稳定性略低于加标记的方案:

import inspect
from your_module import check_user

def is_decorated_with_check_user(func):
    current_func = func
    while current_func:
        closure_vars = inspect.getclosurevars(current_func)
        if closure_vars.globals.get('check_user') is check_user:
            return True
        current_func = getattr(current_func, "__wrapped__", None)
    return False

测试用例的逻辑和方案1一致,直接调用这个判断函数即可。

内容的提问来源于stack exchange,提问作者HeyMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 06:15:03