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 def 和 await | 支持装饰异步函数 |
成功处理 | 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/except | async try/except |
适用场景 | 普通函数/方法 | asyncio协程 |
3.2 核心价值
- 执行过程透明化:完整记录函数调用参数
- 结果自动标记:明确区分PASS/FAIL状态
- 异常信息完整:保留原始错误堆栈
- 非侵入式集成:通过装饰器无缝添加功能
- 统一日志格式:标准化测试输出格式
四、高级应用场景
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})
这种异步日志装饰器模式为自动化测试提供了强大的执行追踪能力,通过非侵入式的方式增强测试的可观察性,是构建健壮测试框架的重要组件。
「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀