zoukankan      html  css  js  c++  java
  • 【Robot Framework 项目实战 04】基于抓包,生成RF关键字及 自动化用例

    背景

    因为服务的迁移,Jira版本的更新,很多接口文档的维护变少,导致想要编写部分服务的自动化测试变得尤为麻烦,很多服务,尤其是客户端接口需要通过抓包的方式查询参数来编写自动化用例,但是过程中手工重复操作过多,不利于RF用例的快速覆盖,本文给大家介绍如何通过解析抓包拦截的数据,转化为测试关键字并生成测试用例。

    实现

    抓包

    如何安装抓包工具在本文就不赘述了,抓包,过滤出想要的数据,导出,保存的格式注意选择为har

    数据解析

    感兴趣的小伙伴可以直接查看导出的har文件内容,它是一个标准的JSON格式的数据,所有的请求数据都在data["log"]["entries"]下。

    需要注意的有以下几点,

    注意点 解决方法
    接口返回数据一般使用的base64进行加密 base64.b64decode()
    标准JSON null等参数与Python不一致 replace("true", "True")
    method=Get时,request["queryString"]
    request["postData"]["text"] request["postData"]["params"]
    header中存在多个无需使用的信息,abandon_headers

    根据请求数据生成关键字名称

    def gen_filename(url, method):
        """
        根据url生成方法名
        :param url:
        :param method:
        :return:
        """
        filename = ""
        path = str(url).split("/")
        # print(path)
        # print(len(path))
        if len(path) == 2 and method == "GET":
            filename = filename + path[1].split("?")[0]
            return filename
        if len(path) == 2 and method == "DELETE":
            filename = filename + path[1].split("?")[0]
            return filename
    
        for i in range(len(path)):
            if i == 1:
                filename = filename + path[i]
                if "." in filename:
                    filename = filename.split(".")[1]
                filename = filename + "_"
                continue
            if i == 2:  # 第一个path小写
                if "?" in path[i]:
                    filename = filename + path[i].capitalize().split("?")[0]
                    break
                filename = filename + path[i]
                continue
            if i == len(path) - 1 and method.upper() == "GET":
                filename = filename + path[i].capitalize().split("?")[0]
                break
            filename = filename + path[i].capitalize()
        return filename
    

    完整代码

    #! /usr/bin/python
    # coding:utf-8 
    """ 
    @author:Bingo.he 
    @file: har_parse.py 
    @time: 2019/01/01
    """
    import os
    import json
    import xlrd
    import copy
    import base64
    from apitest.Common.Testscript.utils.logger import logger
    from xlutils import copy
    
    
    def save_suits(keyword_filename, datas, file_path, ignore_same_file=None):
        """保存excel数据
        :param ignore_same_file:
        :param file_path:
        :param keyword_filename:
        :param datas:
        :return:
        """
        book = xlrd.open_workbook("source_xls/templates/kw_template.xls", formatting_info=True, encoding_override="utf8")
        new_book = copy.copy(book)  # 复制读取的Excel
        sheet = new_book.get_sheet(0)  # 取第一个sheet页
        line_num = 1
        parameter, value, description, parameter_type, data_type, exp, _type, url, group, documentation, headers, _ = datas
    
        if len(str(exp)) > 30000:
            exp = {"data": "返回数据过大"}
        sheet.write(line_num, 0, u'%s' % parameter)
        sheet.write(line_num, 1, u'%s' % value)
        sheet.write(line_num, 2, u'%s' % description)
        sheet.write(line_num, 3, u'%s' % parameter_type)
        sheet.write(line_num, 4, u'%s' % data_type)
    
        try:
            pass
        except Exception as e:
            logger.error(e)
            if isinstance(exp, dict):
                pass
            else:
                exp = str(exp[2:-1])
        sheet.write(line_num, 5, u'%s' % eval(json.dumps(str(exp))))
        sheet.write(line_num, 6, u'%s' % _type)
        sheet.write(line_num, 7, u'%s' % url)
        sheet.write(line_num, 8, u'%s' % group)
        sheet.write(line_num, 9, u'%s' % documentation)
        sheet.write(line_num, 10, u'%s' % headers)
        if not os.path.exists(file_path):
            os.makedirs(file_path)
        if keyword_filename:
            target_filename = os.path.abspath(os.path.join(file_path, '{}.xls'.format(keyword_filename)))
            if os.path.exists(target_filename) and not ignore_same_file:
                raise Exception
            new_book.save(target_filename)  # 保存修改过后复制的Excel
        logger.info("关键字【{}】文件保存成功,保存于【{}】目录".format(keyword_filename, file_path))
    
    
    class HarParse:
        @staticmethod
        def get_har_data(har_filename):
            """读取传入的har文件,返回 关键字文件名 及 对应数据 的键值对
            :param har_filename:
            :return:
            """
    
            with open(har_filename, "r", encoding="utf8") as f:
                data = f.readlines()
                return json.loads(data[0])["log"]["entries"]
    
        def parse_data(self, har_file, domain_endpoint):
            reqs = self.get_har_data(har_file)
            xls_datas = {}
    
            for req in reqs:
                request = req["request"]
                headers_str = self.gen_header_data(request["headers"])
    
                method = request["method"]
                url = request["url"].split(domain_endpoint)[1]
    
                resp = req["response"]
                base64_content_text = resp["content"]["text"]
    
                try:
                    resp_text = base64.b64decode(base64_content_text).decode().replace("false", "False").
                        replace("null", "None").replace("true", "True")
                except Exception as e:
                    logger.error("请求【{}】method:【{}】返回结果-base64-转化出错".format(request["url"], method))
                    logger.error("错误原因:【{}】".format(e))
                    continue
                filename = self.gen_filename(url, method)
    
                keys = [i.upper() for i in xls_datas.keys()]
                if filename.upper() in keys:
                    filename = filename + method.upper()
    
                content_type = "urldecode"
    
                if method.upper() == "GET":
                    url = url.split("?")[0]
                    query_strs = request["queryString"]
    
                    post_data = {}
                    for query_str in query_strs:
                        post_data[query_str["name"]] = query_str["value"]
                else:
                    content_type = "json"  # application/json
                    try:
                        post_data = request["postData"]["text"]
                    except KeyError:
                        post_data = request["postData"]["params"]
    
                # request["headers"]
                data = ["data", post_data, "", content_type, "", resp_text, method, url, "", self.doc(), headers_str,
                        request["headers"]]
    
                xls_datas[filename] = data
    
                logger.info("抓取的URL为【{}】".format(request["url"]))
                logger.info("获取对应PATH为【{}】".format(url))
                logger.info("对应将生成的文件名称为【{}】".format(filename))
                logger.info("=============================分割线===============================")
    
                # logger.info(json.dumps(xls_datas.keys(), indent=4, ensure_ascii=False))
            return xls_datas
    
        @staticmethod
        def gen_filename(url, method):
            """
            根据url生成方法名
            :param url:
            :param method:
            :return:
            """
            filename = ""
            path = str(url).split("/")
            # print(path)
            # print(len(path))
            if len(path) == 2 and method == "GET":
                filename = filename + path[1].split("?")[0]
                return filename
            if len(path) == 2 and method == "DELETE":
                filename = filename + path[1].split("?")[0]
                return filename
    
            for i in range(len(path)):
                if i == 1:
                    filename = filename + path[i]
                    if "." in filename:
                        filename = filename.split(".")[1]
                    filename = filename + "_"
                    continue
                if i == 2:  # 第一个path小写
                    if "?" in path[i]:
                        filename = filename + path[i].capitalize().split("?")[0]
                        break
                    filename = filename + path[i]
                    continue
                if i == len(path) - 1 and method.upper() == "GET":
                    filename = filename + path[i].capitalize().split("?")[0]
                    break
                filename = filename + path[i].capitalize()
            return filename
    
        @staticmethod
        def gen_header_data(headers):
            headers_str = ""
            for i in headers:
                abandon_headers = ["Host", "User-Agent", "Accept-Encoding", "Accept", "Connection", "Content-Length"]
                if i["name"] in abandon_headers:
                    continue
                headers_str = headers_str + i["name"] + "=" + i["value"] + "    "
    
            return headers_str
    
        @staticmethod
        def doc():
            return """
            ...    【功能】 
            ...
            ...    【参数】
            ...    url: 请求域名
            ...    data: 请求参数
            ...
            ...    【返回值】
            ...    Ret: response对象
                    """
    
  • 相关阅读:
    音频文件的属性
    判断UITextField.text是否为空(转)
    digital audio properties
    对scrollView的属性contentSize contentOffset contentInset个人理解
    OC定义变参函数
    va_list、va_start、va_arg、va_end的原理与使用(转载)
    游标笔记
    oracle中删除重复数据
    IIS无法启动,错误代码127[转自Alibaba DBA Team]
    推进游标是Fetch不是Petch!~!
  • 原文地址:https://www.cnblogs.com/Detector/p/10476473.html
Copyright © 2011-2022 走看看