44. 改造异步装饰器记录异步测试执行过程与结果

44. 改造异步装饰器记录异步测试执行过程与结果

一、异步日志装饰器解析

1.1 核心代码结构

from functools import wraps
from chap6.decorators import log  # 导入日志模块

def logs(func):
    """异步日志装饰器"""
    @wraps(func)  # 保留函数元数据
    async def wrap_func(*args, **kwargs):
        # 捕获函数参数
        tuple_args = args
        dict_kwargs = kwargs
        
        try:
            # 执行异步函数
            await func(*args, **kwargs)
            
            # 记录成功日志
            log.debug(
                f'{func.__name__}(*args:tuple = *{tuple_args}, **kwargs:dict = **{dict_kwargs})',
                extra={'status': 'PASS'}
            )
        except Exception:
            # 记录异常日志
            log.exception(
                f'{func.__name__}(*args:tuple = *{tuple_args}, **kwargs:dict = **{dict_kwargs})',
                exc_info=True,
                extra={'status': 'FAIL'}
            )
            raise  # 重新抛出异常

    return wrap_func

1.2 关键功能说明

功能点实现方式作用描述
参数捕获tuple_args = args记录调用时的实际参数
异步支持async defawait支持装饰异步函数
成功处理log.debug + PASS 状态记录函数执行成功
异常处理log.exception + FAIL 状态记录异常堆栈信息
异常传播raise保持原函数的异常行为
元数据保留@wraps(func)保留原函数名等属性

二、实际应用示例

2.1 定义异步测试函数

@logs  # 应用日志装饰器
async def test_login(driver):
    """登录功能测试"""
    await driver.get('https://example.com/login')
    await driver.send_keys('id', 'username', text='testuser')
    await driver.send_keys('id', 'password', text='password123')
    await driver.click('id', 'login-btn')
    title = await driver.title()
    if title != 'Dashboard':
        raise ValueError(f'预期标题"Dashboard", 实际"{title}"')

2.2 成功执行场景

# 调用测试函数
await test_login(driver)

# 日志输出示例
"""
2023-12-01 14:30:45 - demo_log - DEBUG - PASS - 
test_login(*args:tuple = *(<Driver object>,), **kwargs:dict = **{})
"""

2.3 失败执行场景

# 调用测试函数(错误密码)
await test_login(driver, password='wrong')

# 日志输出示例
"""
2023-12-01 14:31:22 - demo_log - ERROR - FAIL - 
test_login(*args:tuple = *(<Driver object>,), **kwargs:dict = **{'password': 'wrong'})
Traceback (most recent call last):
  File "test_demo.py", line 15, in wrap_func
    await func(*args, **kwargs)
  File "test_demo.py", line 8, in test_login
    raise ValueError(f'预期标题"Dashboard", 实际"{title}"')
ValueError: 预期标题"Dashboard", 实际"Login Failed"
"""

三、设计优势分析

3.1 与传统装饰器对比

特性同步装饰器异步装饰器
函数支持同步函数异步函数
执行方式直接调用需要await调用
错误处理try/exceptasync try/except
适用场景普通函数/方法asyncio协程

3.2 核心价值

  1. 执行过程透明化:完整记录函数调用参数
  2. 结果自动标记:明确区分PASS/FAIL状态
  3. 异常信息完整:保留原始错误堆栈
  4. 非侵入式集成:通过装饰器无缝添加功能
  5. 统一日志格式:标准化测试输出格式

四、高级应用场景

4.1 测试用例自动标记

@logs
async def test_checkout(driver, user, product):
    # 下单流程测试
    ...

# 执行后自动生成日志:
# test_checkout(*args:tuple = *(<Driver>,), **kwargs:dict = **{'user': 'Alice', 'product': 'Laptop'})

4.2 参数化测试追踪

import pytest

@pytest.mark.parametrize("username,password", [
    ("admin", "admin123"),
    ("test", "test123")
])
@logs
async def test_login_param(driver, username, password):
    # 参数化登录测试
    ...
    
# 每次调用生成独立日志记录

4.3 性能监控扩展

def logs(func):
    @wraps(func)
    async def wrap_func(*args, **kwargs):
        start_time = time.monotonic()  # 记录开始时间
        try:
            result = await func(*args, **kwargs)
            elapsed = time.monotonic() - start_time
            log.debug(f"{func.__name__} 执行成功 | 耗时: {elapsed:.2f}s", ...)
            return result
        except Exception:
            elapsed = time.monotonic() - start_time
            log.exception(f"{func.__name__} 执行失败 | 耗时: {elapsed:.2f}s", ...)
            raise
    return wrap_func

五、最佳实践建议

5.1 安全增强

# 敏感参数过滤
def sanitize_kwargs(kwargs):
    sensitive_keys = {'password', 'token', 'credit_card'}
    return {k: '***' if k in sensitive_keys else v for k, v in kwargs.items()}

# 在装饰器中应用
log.debug(f"{func.__name__}(...{sanitize_kwargs(dict_kwargs)}")

5.2 日志优化

# 精简日志格式
log_format = '%(asctime)s - %(levelname)s - %(message)s'

# 使用结构化日志
log.info(json.dumps({
    "function": func.__name__,
    "status": "PASS",
    "args": str(tuple_args),
    "kwargs": str(dict_kwargs),
    "time": datetime.now().isoformat()
}))

5.3 错误分类

except AssertionError as ae:
    log.warning(f"断言失败: {str(ae)}", ...)
except TimeoutError as te:
    log.error(f"操作超时: {str(te)}", ...)
except Exception as e:
    log.exception("未处理异常", ...)

六、完整集成示例

# test_suite.py
from async_decorators import logs

@logs
async def test_user_registration(driver, user_data):
    # 用户注册测试
    ...

@logs
async def test_payment_process(driver, order):
    # 支付流程测试
    ...

# 执行测试
async def run_tests():
    driver = await create_driver()
    await test_user_registration(driver, {'name': 'Alice', 'email': 'alice@example.com'})
    await test_payment_process(driver, {'order_id': 123, 'amount': 100})

这种异步日志装饰器模式为自动化测试提供了强大的执行追踪能力,通过非侵入式的方式增强测试的可观察性,是构建健壮测试框架的重要组件。


「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值