【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对象
                """
posted @ 2019-03-05 14:18  _BingoHe  阅读(780)  评论(0编辑  收藏  举报