测试工具(4)解析rap2数据

103 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

大家好~我是小方,欢迎大家关注笋货测试笔记体完记得俾个like

题外话

最近拖更了哈,这周比较忙,被ld抓去商城组那边支援紧急项目,周一传递需求,周五上线,全程算是半个酱油吧,对公司的商城业务不太熟悉,但好在以前经常混迹在电商业务里头,比较熟悉商城的套路!摸了 (摸鱼) 一天大概懂了整个业务流程~

回顾

上次我们讲到了通过百度OCR工具识别rap2登录中的验证码,从而实现登录~那我们今天来实战解析rap2的接口数据,生成我们所需要的接口数据

实践上手

文档分析

1、我们先通过F12看看哪个接口是我们需要的?对~就是你了!

image.png

2、将接口数据复制到www.json.cn/ 我们来看看接口数据结构,看看有哪些信息是需要的

image.png

image.png

image.png

image.png 3、通过分析properties中的数据,发现pos=1为请求头,pos=2为路径参数,pos=3为body参数,name为字段名,value为字段值,parentId=1,没有父节点;parentId!=-1,为父节点

代码解析

上一期中,有小伙伴反馈说,可以输入cookies不?那这次优化一下吧~

实现rap2登录并获取数据

    @classmethod
    def rap_data(cls, id, cookies = None):
        """
        获取接口文档数据
        :param id: 接口文档id
        :param cookies: 非必填,登录的cookies
        :return: 返回json数据
        """
        params = {"id": id}
        if cookies:
            try:
                cls.cookies = dict([i.split("=", 1) for i in cookies.split("; ")])
            except Exception as e:
                raise Exception('cookies格式不对,请重新输入!')
            try:
                res = requests.get(url=UrlConfig.RAP_PROJRCT_URL, params=params, cookies=cls.cookies).json()
            except Exception as e:
                raise Exception('cookies过期了,请重新输入!')
            return res
        else:
            login_result = False
            #判断是否登录成功
            while not login_result:
                login_result = Rap2Data.rap_login()
            res = requests.get(url=UrlConfig.RAP_PROJRCT_URL, params=params, cookies=cls.cookies).json()
            return res

解析关键代码展示:执行主入口

class Rap2Parse(object):

    @classmethod
    def api_data(cls, id, cookies=None, module=None):
        json_obj = Rap2Data.rap_data(id, cookies)
        errMsg = json_obj.get("errMsg")
        #获取报错信息,将其抛出(权限不足、不存在接口文档,接口都会返回errMsg)
        if errMsg:
            errMsg = errMsg + f"请将接口文档授权给{Account.RAP['email']}!"
            raise Exception(errMsg)
        if module is None:
            #模块名不传的话,默认获取所有模块数据
            json_list = json_obj['data']['modules']
        else:
            #模块名传入,获取对应的模块数据
            json_list = jsonpath(json_obj, f"$.data.modules[?(@.name=='{module}')]")
            #校验传入的模块名是否存在
            if not json_list:
                raise Exception(f"{module}模块名不存在")
        # 接口文档标题名,作为后续的文件名
        file_name = json_obj.get('data').get('name')
        #对标题名特殊处理
        special_str = r"[\/\\\:\*\?\"\<\>\|]"
        file_name = re.sub(special_str, "-", file_name)
        data = []
        #遍历模块数据
        for i in json_list:
            modules_data = {}
            #模块名
            modules_data['modules'] = i['name']
            #模块描述
            modules_data['description'] = i['description']
            interfaces = []
            #遍历interfaces接口数据
            for i, dto in enumerate(i['interfaces']):
                cases_data = {}
                #接口id
                cases_data['api_id'] = i + 1
                #接口名
                cases_data['title'] = dto['name']
                #接口描述
                cases_data['description'] = dto['description']
                #接口路径
                cases_data['url'] = dto['url']
                #接口请求方法
                cases_data['method'] = dto['method']
                #获取接口的入参和出参
                properties_list = jsonpath(dto['properties'], f"$.[?(@.scope=='request')]")
                #接口请求头数据
                cases_data['headerData'] = cls.parent_data(properties_list)[2]
                #接口query参数
                cases_data['queryData'] = cls.parent_data(properties_list)[1]
                #接口body参数
                cases_data['data'] = cls.parent_data(properties_list)[0]
                interfaces.append(cases_data)
            modules_data['cases_data'] = interfaces
            data.append(modules_data)
        return data, file_name

组装参数

    @classmethod
    def join_data(cls, json_data, properties, name, type, value, parentId, api_id):
        """
        组装参数
        :param json_data: 字典值(存数据用)
        :param properties: 接口的入参和出参数据
        :param name: 接口名
        :param type: 字段类型
        :param value: 字段值
        :param parentId: 父id
        :param api_id: 所有的参数id
        :return: json_data
        """
        #特殊字符替换
        name = name.replace(".","")
        #没有父id,直接塞进json_data
        if parentId == -1:
            v = cls.change_value(type, value)
            json_data[name] = v
        #有父id且父id在api_id中
        elif parentId != -1 and parentId in api_id:
            #根据父id获取父id的数据
            parent_dto = jsonpath(properties, f"$.[?(@.id=={parentId})]")
            if not parent_dto:
                raise Exception("接口文档维护有误")
            parent_dto = parent_dto[0]
            #如果父的类型为数组
            if parent_dto['type'] == 'Array':
                #找到父的key
                parent_array = cls.search_value(json_data, parent_dto['name'])
                v = cls.change_value(type, value)
                #将子数据挂载在父下面
                parent_array[0][name] = v
            # 如果父的类型为对象
            elif parent_dto['type'] == 'Object':
                # 找到父的key
                parent_object = cls.search_value(json_data, parent_dto['name'])
                v = cls.change_value(type, value)
                # 将子数据挂载在父下面
                parent_object[name] = v
            else:
                raise Exception("父数据类型不支持")
        else:
            pass
            # raise Exception("父数据类型不支持")
        return json_data

递归找对应的key数据

    @classmethod
    def search_value(cls, data, key):
        """
        递归找到所在key的数据
        :param data: 数据
        :param key: 需要找的key
        :return:
        """
        key = key.replace(".", "")
        json_data = JsonSearch(object=data)
        path = json_data.search_first_path(key)
        path_str = cls.path_str(path)
        value = jsonpath(data, path_str)[0]
        return value

解析后数据展示

项目地址:github.com/JokerChat/A…

后续扩展

  • 将数据生成Excel格式的接口自动化用例
  • 将数据生成yaml格式接口自动化用例
  • 将数据生成生成jmeter脚本(jmx)
  • 基于上述功能,做成前端页面,供其他人使用

本期介绍了如何解析rap2接口文档数据,并组装成我们想要的数据,我们下期再见👋🏻👋🏻👋🏻俾个like再走啦