hxz
发布于 2023-09-26 / 70 阅读
0

【接口自动化框架】如何快速定位问题

背景痛点:

落地接口自动化项目过程中,提高团队内部的编码效率和代码可读性一直是重中之重,并且,在自动化用例运行期间,如遇到运行异常或断言失败等问题,如果运行的用例数量过大,在一定程度上,影响了团队内排查定位问题的效率。并且,运行时的具体情况细节,如果仅打印在控制台,当下一次运行开始时,之前的记录都不会得到妥善保存。

罗列痛点问题如下:

一、如果运行过程中遇到问题导致运行中断,新手同学需要从控制台看到实际运行报错的Traceback,再去找到对应的代码行位置,去排查问题;

二、基于问题一,很多新手同学可能会认为,在编码过程中,使用print打印各个请求步骤,进行用例运行的跟踪,但这无疑增加了编码负担;

三、print输出到控制台的结果显示不够具备美观性,在控制台定位问题眼花缭乱

四、运行的结果只在控制台打印,没有规范化日志文件保存,不会保留上一次运行日志;

针对这些痛点问题,需要对接口自动化框架的运行情况增加日志记录跟踪功能,方便定位问题,保留日志记录,并且提高编码效率。

实现细节

首先,团队内部需要定义好日志输出规范,定义各个等级的日志,实现step、info、error级别日志。

其次规范化日志输出格式,记录运行时间和运行类、函数、代码行号,并格式化输出,对输出文本美化,并且按照日志等级分别按严重程度记录日志文件。

然后输出内容到项目logs文件夹下,按日期进行命名,生成.log文件

import functools
import os
import inspect
from datetime import datetime
from colorama import Fore
from main import DIR


def info(text):
    stack = inspect.stack()
    formatted_time = datetime.now().strftime('%H:%M:%S:%f')[:-3]  # 定义日志输出时间
    code_path = f"{os.path.basename(stack[1].filename)}:{stack[1].lineno}"  # 当前执行文件的绝对路径和执行代码行号
    content = f"[INFO]{formatted_time}-{code_path} >> {text}"
    print(Fore.LIGHTBLUE_EX + content)
    str_time = datetime.now().strftime("%Y%m%d")
    with open(file=DIR + '\\logs\\' + f'{str_time}_info.log', mode='a', encoding='utf8') as f:
        f.write(content + '\n')


def step(text):
    stack = inspect.stack()
    formatted_time = datetime.now().strftime('%H:%M:%S:%f')[:-3]  # 定义日志输出时间
    code_path = f"{os.path.basename(stack[1].filename)}:{stack[1].lineno}"  # 当前执行文件的绝对路径和执行代码行号
    content = f"[STEP]{formatted_time}-{code_path} >> {text}"
    print(Fore.LIGHTGREEN_EX + content)
    str_time = datetime.now().strftime("%Y%m%d")
    with open(file=DIR + '\\logs\\' + f'{str_time}_info.log', mode='a', encoding='utf8') as f:
        f.write(content + '\n')


def error(text):
    stack = inspect.stack()
    formatted_time = datetime.now().strftime('%H:%M:%S:%f')[:-3]  # 定义日志输出时间
    code_path = f"{os.path.basename(stack[1].filename)}:{stack[1].lineno}"  # 当前执行文件的绝对路径和执行代码行号
    content = f"[ERROR]{formatted_time}-{code_path} >> {text}"
    print(Fore.RED + content)
    str_time = datetime.now().strftime("%Y%m%d")
    with open(file=DIR + '\\logs\\' + f'{str_time}_info.log', mode='a', encoding='utf8') as f:
        f.write(content + '\n')
    with open(file=DIR + '\\logs\\' + f'{str_time}_error.log', mode='a', encoding='utf8') as f:
        f.write(content + '\n')


def case_log_init(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        class_name = args[0].__class__.__name__  # 获取类名
        method_name = func.__name__  # 获取方法名
        docstring = inspect.getdoc(func)  # 获取方法注释
        print(Fore.LIGHTRED_EX + '-----------------------------------------------')
        info(
            f"【用例{method_name}】开始执行------------------------------------------------")
        info(f'Class Name:{class_name}')
        info(f'Method Name:{method_name}')
        info(f'Test Description:{docstring}')
        func(*args, **kwargs)
        info(f"【用例{method_name}】运行结束------------------------------------------------")

    return inner


def class_case_log(cls):
    """用例的日志装饰器级别"""
    for name, method in inspect.getmembers(cls, inspect.isfunction):
        if name.startswith('testCase'):
            setattr(cls, name, case_log_init(method))
    return cls


最后运用装饰器,给测试用例类增加日志输出功能,测试用例步骤中以step("日志内容")的形式进行调用日志记录功能方法。

这样,框架日志记录功能已实现完毕,下面验证下可用性...

验证可用性

控制台输出如下

生成日志文件如下

可以看到,按照日志级别输出日志,日志生成时间,运行位置(类、函数、代码行号)和运行步骤,请求信息等,都被准确记录到日志文件中持久保存。至此,痛点问题均被解决。