Beispiel #1
0
 def setUp(self):
     """
     测试用例前置条件
     :return:
     """
     self.L = Log("MyTestClass").logger
     self.L.critical("测试准备")
     self.runner = Runner()
     self.case_path = os.path.abspath(".") + "/testCase/"
Beispiel #2
0
class KeyGlobal(object):
    """
    1.RECORD 关键字,将指定的值,存储为全局变量,在任意test case均可直接调用
    2.READ 关键字,读取存储的全局变量
    数据存放到 data_global{} 中
    """
    def __init__(self):
        global global_dict
        self.L = Log("KeyGlobal").logger

    def set_global_key(self, key, value):
        """
        实现RECORD,将value,存储为key的值,全局可用data_global
        :param key:
        :param value:
        :return:
        """
        global_dict[key] = value
        self.L.info("{%s: %s}已设置" % (key, value))

    def get_global_value_by_key(self, key: str, key_type: str = ""):
        """
        给REQUEST\LREQUEST\RESPONSE\LRESPONSE 提供检查方法
        :param key_type:
        :param key:
        :return:
        """
        try:
            if key_type == "REQUEST":
                value = UniversalDataOperation().get_dicts_value_by_key_path(
                    global_dict["data_current"]["req"], key)
            elif key_type == "LREQUEST":
                value = UniversalDataOperation().get_dicts_value_by_key_path(
                    global_dict["data_last"]["req"], key)
            elif key_type == "RESPONSE":
                value = UniversalDataOperation().get_dicts_value_by_key_path(
                    global_dict["data_current"]["resp"], key)
            elif key_type == "LRESPONSE":
                value = UniversalDataOperation().get_dicts_value_by_key_path(
                    global_dict["data_last"]["resp"], key)
            else:
                value = UniversalDataOperation().get_dicts_value_by_key_path(
                    global_dict, key)
            return value
        except KeyError:
            raise Exception("键名异常: %s" % key)
Beispiel #3
0
class TestMain(unittest.TestCase):
    def setUp(self):
        """
        测试用例前置条件
        :return:
        """
        self.L = Log("MyTestClass").logger
        self.L.critical("测试准备")
        self.runner = Runner()
        self.case_path = os.path.abspath(".") + "/testCase/"

    def test_user_login(self):
        """
        测试用户登录
        :return:
        """
        case_path = self.case_path + "user.yaml"
        self.L.info("开始执行测试用例:%s" % case_path)
        self.runner.do_request(case_path)

    def test_user_logout(self):
        """
        测试用户注销
        :return:
        """
        case_path = self.case_path + "user.yaml"
        self.L.info("开始执行测试用例:%s" % case_path)
        self.runner.do_request(case_path)

    def test_customer(self):
        """
        测试苗叔向基地购买流程
        :return:
        """
        case_path = self.case_path + "苗叔向基地购买流程.yaml"
        self.L.info("开始执行测试用例:%s" % case_path)
        self.runner.do_request(case_path)

    def test_user_shop(self):
        """
        测试基地库存
        :return:
        """
        case_path = self.case_path + "Shopbuy.yaml"
        self.L.info("开始执行测试用例:%s" % case_path)
        self.runner.do_request(case_path)
Beispiel #4
0
class KeyRequest(object):
    """
    1.解析data_file中关键字REQUEST、GREQUEST、LREQUEST、IMAGE的用法,并执行请求,将请求结果按str类型返回给调用方
    2.REQUEST() 关键字,返回当前请求中参数值,如REQUEST(id),则返回当次请求中id的值 在data_current中获取
    3.LREQUEST() 关键字,返回上一次请求中参数值,如LREQUEST(id),则返回上次请求中id的值 在data_last中获取
    4.IMAGE() 关键字,参数是图片路径,用户请求中,说明该接口参数是图片信息
    """
    def __init__(self):
        self.L = Log("KeyRquest").logger
        self.kg = KeyGlobal()

    def get_current_request_info_by_argument(
            self, field_name: str) -> str or dict or list:
        """
        解析关键字REQUEST()
        :param field_name: 当前请求中那个参数的值
        :return:
        """
        try:
            self.L.info("解析关键字REQUEST,解析路径为: %s" % field_name)
            result = self.kg.get_global_value_by_key(field_name, "REQUEST")
            self.L.debug("解析REQUEST(%s)的结果是:%s" % (field_name, result))
            return result
        except Exception as e:
            raise Exception("解析关键字REQUEST数据异常,异常信息:%s" % e)

    def get_last_request_info_by_argument(
            self, field_name: str) -> str or dict or list:
        """
        解析关键字LREQUEST()
        :param field_name: 上次请求中那个参数的值
        :return:
        """
        try:
            self.L.info("解析关键字LREQUEST,解析路径为: %s" % field_name)
            result = self.kg.get_global_value_by_key(field_name, "LREQUEST")
            self.L.debug("解析LREQUEST(%s)的结果是:%s" % (field_name, result))
            return result
        except Exception as e:
            raise Exception("解析关键字LREQUEST数据异常,异常信息:%s" % e)

    def get_image_info(self, image_name: str) -> str:
        """
        解析关键字IMAGE()
        :param image_name: 图片详细路径或名字
        :return:
        """
        try:
            return image_name
        except Exception as e:
            raise Exception("解析关键字IMAGE数据异常,异常信息:%s" % e)
Beispiel #5
0
class KeySquery(object):
    """
    SQUERY(sql) 执行sql,将数据结果以list形式返回,如果list长度只有一个,则直接返回值
    """
    def __init__(self):
        self.L = Log("KeySquery").logger

    def get_sql_result(self, sql: str) -> str or list or int or float:
        """
        SQUERY(sql) 执行sql,将数据结果以list形式返回,若只有一个元素则直接返回一个元素
        :param sql:
        :return:
        """
        try:
            # 执行SQL
            self.L.info("准备执行SQL:%s" % sql)
            cursor = self.__connect_database().cursor()
            cursor.execute(sql)
            result_tmp = cursor.fetchall()
            self.L.info("SQL执行结果 %s" % result_tmp)

            # 将返回的SQL结果序列成一维list
            result = []
            for x in result_tmp:
                for y in list(x.values()):
                    result.append(y)

            # 多个数据结果以list形式返回,一个元素则直接返回一个元素
            if len(result) < 2:
                return result[0]
            else:
                return result
        except Exception as e:
            raise Exception("执行SQL异常 %s" % e)

    def __connect_database(self):
        """
         链接数据库
        """
        try:
            kg = KeyGlobal()
            config = kg.get_global_value_by_key("baseInfo.dataBase")
            self.L.debug("host: %s, database: %s" %
                         (config["host"], config["database"]))
            db = pymysql.connect(host=config["host"],
                                 user=config["user"],
                                 port=config["port"],
                                 password=config["password"],
                                 database=config["database"],
                                 cursorclass=pymysql.cursors.DictCursor)
            return db
        except ConnectionError as e:
            raise ConnectionError("连接数据库错误 %s" % e)
Beispiel #6
0
class KeyResponse(object):
    """
    RESPONSE(路径) 读取响应数据data_current 中的RESPONSE值字段,并将值取出返回str
    LRESPONSE() 关键字,返回上一次请求data_last中参数值str,如LREQUEST(id),则返回上次请求中id的值
    特殊的,当入参中包含迭代器时,需要迭代查询结果,并按list形式返回,迭代标识符为 __iterations__  ,如传入的参数为key[__iterations__]["status"],返回key下每个模块中的status
    """
    def __init__(self):
        self.L = Log("KeyResponse").logger
        self.li = []
        self.kg = KeyGlobal()

        # self.global_data = json.loads('{"name":"中国","province":[{"name":"黑龙江","cities":{"city":["哈尔滨","大庆"]}},{"name":"广东","cities":{"city":["广州","深圳","珠海"]}},{"name":"台湾","cities":{"city":["台北","高雄"]}},{"name":"新疆","cities":{"city":["乌鲁木齐"]}}]}')

    def get_current_response_message(self,
                                     field_name: str) -> str or dict or list:
        """
        解析关键字RESPONSE()
        :param field_name: 当前请求中那个参数的值
        :return:
        """
        try:
            self.L.info("解析关键字RESPONSE,解析路径为: %s" % field_name)
            result = self.kg.get_global_value_by_key(field_name, "RESPONSE")
            self.L.debug("解析RESPONSE(%s)的结果是:%s" % (field_name, self.li))
            return result
        except Exception as e:
            raise Exception("解析关键字RESPONSE数据异常,异常信息:%s" % e)

    def get_last_response_message(self,
                                  field_name: str) -> str or dict or list:
        """
        解析关键字LRESPONSE()
         LRESPONSE() 返回接口响应中的,key(json中的数据路径),下的数据
        """
        try:
            self.L.info("解析关键字LRESPONSE,解析路径为: %s" % field_name)
            result = self.kg.get_global_value_by_key(field_name, "LRESPONSE")
            self.L.debug("解析LRESPONSE(%s)的结果是:%s" % (field_name, self.li))
            print(result)
        except Exception as e:
            raise Exception("解析关键字LRESPONSE数据异常,异常信息:%s" % e)
Beispiel #7
0
 def __init__(self):
     self.L = Log("KeyRquest").logger
     self.kg = KeyGlobal()
Beispiel #8
0
 def __init__(self):
     """
     请求类初始化本类日志
     """
     self.L = Log("SendRequest").logger
class UniversalDataOperation(object):
    def __init__(self):
        self.iterative_values = False
        self.L = Log("KeyGeneralMethods").logger

    def get_dicts_value_by_key_path(self, dicts: dict, key_path: str) -> str or list:
        """
        字典路径下的数据获取
        :param dicts: 需要解析的源数据
        :param key_path: 解析的路径,用"."号隔开,如:content.pn
        :return: 返回解析结果
        :return: str or list
        """
        # 将传入的字符串格式化为list
        key_path_r = key_path.split(".")

        # 调用私有方法进行解析
        self.iterative_values = "__iterations__" in key_path_r
        result = self.__get_dicts_value_by_key_path(dicts, key_path_r)

        # 若返回到是字符串直接返回,若返回的是list且是一个元素返回字符串,若返回的是list且是多个元素返回一维list
        if isinstance(result, list):
            if len(result) == 1:
                self.L.debug("通过路径%s,查找到的数据是%s" % (key_path, result[0]))
                return result[0]
            else:
                self.L.debug("通过路径%s,查找到的数据是%s" % (key_path, result))
                return result
        else:
            self.L.debug("通过路径%s,查找到的数据是%s" % (key_path, result))
            return result

    def __get_dicts_value_by_key_path(self, dicts: dict or list, key_path: list) -> str or list:
        """
        实现字典值索引
        :param dicts: 需要解析的源数据
        :param key_path: 解析的路径,按list形式传入
        :return: 返回解析结果
        """

        try:
            # 获取传入的字符串中的第一个key,
            i = key_path[0]

            # 判断当前是否为查找路径终点,若为终点,则直接取之返回。 否则继续往后查找字符串
            if len(key_path) > 1:
                # 若查找的路径不是叶子节点,则删除当前节点
                del key_path[key_path.index(i)]

                # 传入的参数是关键字"__iterations__"时,直接使用当前传入的字典
                if "__iterations__" == i:
                    return self.__get_dicts_value_by_key_path(dicts, key_path)

                # 传入的参数是数字时,从当前路径中,取出指定id下的值
                elif i.isdigit():
                    return self.__get_dicts_value_by_key_path(dicts[int(i)], key_path)

                # 当传入的是一个字符串时,取出对应key下的value
                else:

                    # 取值时,若是在list中,需要到list中去取对应key的值
                    if isinstance(dicts, list):
                        temp_list = []
                        for x in dicts:
                            temp_list.append(x[i])
                        return self.__get_dicts_value_by_key_path(temp_list, key_path)

                    # 取值时,若是在dict中,直接取对应key的值
                    else:
                        return self.__get_dicts_value_by_key_path(dicts[i], key_path)

            # 判断当前查找是否为叶子节点,并返回最终叶子节点值
            else:

                # 叶子节点传入的参数是关键字"__iterations__"时,直接使用当前传入的字典
                if "__iterations__" == i:

                    # 叶子节点
                    if isinstance(dicts, list):
                        return self.__list_flatten(dicts)
                    else:
                        return dicts
                        # return dicts[i]

                # 叶子节点传入的参数是数字时,返回指定节点值
                elif i.isdigit():

                    # 在叶子节点前,若出现过关键字"__iterations__"时,是返回每个节点下的第一个值
                    if self.iterative_values:
                        tmp = []
                        for x in dicts:

                            # 检查传入的值是否超过list下标,若超过不做处理
                            if len(x) > int(i):

                                # 若传入的是list,直接取出对应id的值
                                if isinstance(x, list):
                                    tmp.append(x[int(i)])

                                # 若传入的是字符串,直接取出对应的值
                                else:
                                    tmp.append(x)
                        return tmp

                    # 在叶子节点前,若没出现过关键字"__iterations__"时,直接返回指定的值
                    else:
                        return dicts[int(i)]

                # 叶子节点传入的参数是字符串时,返回指定节点值
                else:

                    # 取值时,若是在list中,需要到list中去取对应key的值
                    if isinstance(dicts, list):
                        temp_list = []
                        for x in dicts:
                            temp_list.append(x[i])
                        return temp_list

                    # 取值时,若是在字典中,直接取出对应值
                    else:
                        return dicts[i]

        except Exception as e:
            raise Exception("\n在内存数据:\n%s中\n未找到键:%s\nKeyError:%s" % (dicts, key_path, e))

    def __list_flatten(self, list_src: list) -> list:
        """
        用于多层嵌套list解包,还原到1层list
        :param list_src:
        :return:
        """
        tmp = []
        for i in list_src:
            if type(i) is not list:
                tmp.append(i)
            else:
                tmp.extend(self.__list_flatten(i))
        return tmp
Beispiel #10
0
class ProduceCaseYaml(object):
    """
    根据服务配置, 自动生在/testCase/templates下生成Case的Yaml模板
    """
    def __init__(self):
        self.L = Log("ProduceCaseYaml").logger

    def get_paths_yaml(self, file_name: str, host_name: str) -> None:
        """
        通过Swagger V2获取api文档
        :param file_name: 想要存储yaml模板文件的文件名
        :param host_name: 各服务域名
        :return: 获取文档方法无需返回
        """
        json_content = SendRequest().get(str(host_name) + '/v2/api-docs')
        # 获取所有的paths节点
        paths = json.loads(json_content)["paths"]
        path_detail_list = []
        for p in paths:
            para_desc_list = []
            try:
                desc = paths[p]["post"].get("tags", [])[0]
                para_desc_list.append(desc)
                # L.logger.debug("{'%s': '%s'}" % (p, desc))
                paras = paths[p]["post"].get("parameters", [])
            except KeyError:
                desc = paths[p]["get"].get("tags", [])[0]
                para_desc_list.append(desc)
                # L.logger.debug("{'%s': '%s'}" % (p, desc))
                paras = paths[p]["get"].get("parameters", [])
            p_dict = {}
            if paras is None:
                pass
            else:
                for para in paras:
                    p_dict[para['name']] = u"%s_%s_%s" % (
                        para.get('type',
                                 'noType'), para.get('required', 'noRequired'),
                        para.get('description', 'noDescription'))
            para_desc_list.append(p_dict)
            path_detail_list.append({p: para_desc_list})
        # demand_list = sorted(path_detail_list)
        now = time.strftime("_%Y-%m-%d_%H%M%S", time.localtime())
        # L.logger.debug(path_detail_list)
        current_path = os.path.dirname(os.path.abspath(__file__))
        if not os.path.exists(current_path + "/templates"):
            os.makedirs(current_path + "/templates")
        with codecs.open('./templates/' + str(file_name) + now + '.yaml', 'a',
                         'utf-8') as f:
            for item in path_detail_list:
                for k, v in item.items():
                    if isinstance(v[1], dict):
                        f.write('\n%s:' % k)
                        f.write('''
    baseInfo:
        author:
        time: 20180931
        logInfo: Debug
        directExecution: True
        generatePython: False
        requestMethod: POST
        requestHeaders: {'Host':'www.super-ping.com','Connection':'keep-alive','Cache-Control':'max-age=0','Accept':'text/html,*/*;q=0.01','X-Requested-With':'XMLHttpRequest','User-Agent':'Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/41.0.2272.89Safari/537.36','DNT':'1','Referer':'http://www.super-ping.com/?ping=www.google.com&locale=sc','Accept-Encoding':'gzip,deflate,sdch','Accept-Language':'zh-CN,zh;q=0.8,ja;q=0.6'}
        serverAddress: %s
        dataBase:
            host: 39.104.28.40
            port: 3306
            user: root
            password: YYJNo$QsaaSjgb8U3JoigB
            database: %s
    interfaceParameters:
        -
    ''' % (host_name, file_name.replace("_", "-").lower()))
                        for x, y in v[1].items():
                            f.write('      %s:\n    ' % x)
                    f.write('interfaceAsserts:\n        -\n')

    def add_latest_yaml(self):
        for key, host in hosts.items():
            try:
                self.get_paths_yaml(key, host)
            except Exception as e:
                self.L.error("错误信息: %s" % e)
Beispiel #11
0
class Dispatcher(object):
    def __init__(self):
        """
        解析参数中的key或value信息,并返回各自关键字执行结果
        """
        self.L = Log("Dispatcher").logger

    def key_dispatcher(self, t_key_string: object, record_value="") -> object:
        """
        此为本类函数入口点, 将入参字符串转为 元组 待递归解析
        :param t_key_string: 解析由Runner.py传入的字符串
        :param record_value: 默认为空, 仅适用于RECORD关键字字典存值使用
        :return: 返回 递归解析并调用路由后 的结果字符串
        """
        if isinstance(t_key_string, str) is False:
            return t_key_string
        else:
            return self.__key_dispatcher_realize((t_key_string, ), record_value)

    def __key_dispatcher_realize(self, t_key: tuple, record_value: str = "") -> str:
        """
        解析由key_dispatcher传入的 (待解析字符串, ) 元组, 递归解析字符串路中的关键字,
        路由匹配调用各关键字类(如: KeyRequest, KeySquery)返回调用后结果字符串
        :param t_key: 由runner调用时传入的字符串key转为的(key, )元组
        :param record_value: 默认为空, 仅适用于RECORD关键字字典存值使用
        :return: 若还可递归, 继续以 (递归函数本身, 关键字, 参数) 的元组 为入参 调用函数本身; 若无法递归 则返回字符串
        """
        # 所有传入字符串 以 左括号 做字符串切片 以解析 关键字 和 入参
        if t_key[0].find('(') == -1:
            # 最后的字符串已不包含左括号
            return t_key[0]
        else:
            # 以第一个左括号位置切片 解析 关键字 和 入参
            left_str = (t_key[0][:t_key[0].find('(')])
            # 去掉 待解析字符串中的 首尾括号; 否则 下次左括号位置为0时, 会导致解析错误
            right_str = (t_key[0][t_key[0].find('(')+1:-1])
            self.L.info("关键字: %s; 参数: %s" % (left_str, right_str))
            return self.__key_route((left_str, self.__key_dispatcher_realize((right_str, left_str))), record_value)

    def __key_mapper(self, check_str: str, except_key: str) -> bool:
        """
        解析由递归函数传入字符串check_str中是否含有期望的关键字except_key, 如REQUEST, LREQUEST, RESPONSE等
        :param check_str: 由递归函数传入字符串
        :param except_key: 期望的关键字except_key, 如REQUEST, LREQUEST, RESPONSE等
        :return: 匹配则返回True, 反之则反
        """
        result = check_str.split(" ")[-1:][0] == except_key
        self.L.debug("%s == %s -> %s" % (check_str, except_key, result))
        return result

    def __key_route(self, key_tuple: tuple, record_value: str = "") -> str:
        """
        解析由key_dispatcher函数传入的(key_dispatcher对象, 关键字, 参数)的元组,
        匹配调用各关键字类(如: Request(content.id))返回调用各关键字类的结果字符串
        :param key_tuple: 由key_dispatcher函数传入的(key_dispatcher对象, 关键字, 参数)的元组
        :param record_value: 默认为空, 仅适用于RECORD关键字字典存值使用
        :return: 调用各关键字类的结果字符串
        """
        # todo: 仅与KeyRequest完成联调, 其他类待联调. 递归最后一层不出日志(情况未知), 尚无其他副作用
        self.L.debug("left: %s | right: %s" % (key_tuple[0], key_tuple[1]))
        if self.__key_mapper(key_tuple[0], "REQUEST"):
            self.L.info("REQUEST is CALLED")
            kr = KeyRequest()
            return kr.get_current_request_info_by_argument(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "LREQUEST"):
            self.L.info("LREQUEST is CALLED")
            kr = KeyRequest()
            return kr.get_last_request_info_by_argument(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "RESPONSE"):
            self.L.info("RESPONSE is CALLED")
            kres = KeyResponse()
            return kres.get_current_response_message(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "LRESPONSE"):
            self.L.info("LRESPONSE is CALLED")
            kres = KeyResponse()
            return kres.get_last_response_message(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "RECORD"):
            self.L.info("RECORD is CALLED")
            kg = KeyGlobal()
            return kg.set_global_key(key_tuple[1], record_value)
        elif self.__key_mapper(key_tuple[0], "READ"):
            self.L.info("READ is CALLED")
            kg = KeyGlobal()
            return kg.get_global_value_by_key(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "SQUERY"):
            self.L.info("SQUERY is CALLED")
            sq = KeySquery()
            return sq.get_sql_result(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "FAKER"):
            self.L.info("FAKER is CALLED")
            kf = KeyFaker()
            return kf.get_some_things(key_tuple[1])
        elif self.__key_mapper(key_tuple[0], "REGEX"):
            self.L.info("REGEX is CALLED")
            # return "REGEX"
        else:
            raise Exception('非法关键字: %s'
                            '\n合法的关键字:'
                            '\nREQUEST 用于立即发送网络请求, '
                            '\nLREQUEST 用于获取上次请求, '
                            '\nRESPONSE 用于立即获取网络响应, '
                            '\nLRESPONSE 用于获取上次网络响应, '
                            '\nSQUERY 用于查询数据库, '
                            '\nRECORD 用于存储全局缓存, '
                            '\nREAD 用于读取全局缓存, '
                            '\nFAKER 用于伪造数据, '
                            '\nREGEX 用于正则校验'
                            '' % str(key_tuple[0]))
Beispiel #12
0
class FileOperation(object):
    def __init__(self, file_name: str):
        """
        文件操作类,传入文件地址,将文件读入缓存中备用
        """
        self.L = Log("FileOperation").logger
        self.fileName = file_name

    def get_file_details(self) -> dict:
        """
        将yaml按标准进行读取到缓存中,可以参照http://www.bejson.com/validators/yaml_editor/ 格式化效果
        将数据存放到data_file{}中
        :return:
        """
        self.L.critical("进入get_file_details")
        # 获取当前所处的文件夹上上一级文件夹的绝对路径
        try:
            cur_path = os.path.abspath('../..')
            # 获取yaml文件路径
            yaml_path = os.path.join(cur_path, self.fileName)
            # open方法打开直接读出来
            yaml_open = open(yaml_path, 'r', encoding='utf-8')
            # 用load方法转为字典,存放在data_files内
            data_file = yaml.load(yaml_open)
            self.L.debug('yaml文件解析为:%s' % data_file)
            return data_file
        except Exception as e:
            self.L.debug('yaml文件解析错误', e)

    def _format_checker(self):
        """
        检查文件请求数与断言数是否一致。
        :return:
        """
        data_files = {}
        try:
            data_file = self.get_file_details()
            for key in data_file:
                dict1 = data_file.get(key)
                data_keys = tuple(dict1.keys())
                # 判断yaml文件字段是否缺失
                if len(data_keys) == 3:
                    self.L.info("yaml文件接口:%s字段数正确" % key)
                    # 判断yaml文件字段名是否正确
                    if data_keys[0] == 'baseInfo':
                        if data_keys[1] == 'interfaceParameters':
                            if data_keys[2] == 'interfaceAsserts':
                                self.L.info("yaml文件接口:%s字段名正确" % key)
                                # 判断yaml文件内的interfaceParameters的case数和interfaceAsserts内的断言数是否对等
                                inf_para = dict1['interfaceParameters']
                                inf_asse = dict1['interfaceAsserts']
                                if len(inf_para) == len(inf_asse):
                                    self.L.info(
                                        "yaml文件接口:%s interfaceParameters的case数和interfaceAsserts"
                                        "内的断言数相同" % key)
                                    # 判断yaml文件的baseInfo的必填项是否缺失
                                    base_info = dict1.get("baseInfo")
                                    if "requestMethod" in base_info:
                                        if "serverAddress" in base_info:
                                            self.L.info(
                                                "yaml文件接口:%s baseInfo内的必填项未缺失"
                                                % key)
                                            # 将检查通过的接口请求数据放入data_files{}中
                                            data_files[key] = dict1
                                        elif "serverAddress" not in base_info:
                                            self.L.debug(
                                                "yaml文件接口:%s baseInfo内的serverAddress字段缺失"
                                                % key)
                                    elif "requestMethod" not in base_info:
                                        self.L.debug(
                                            "yaml文件接口:%s baseInfo内的requestMethod字段缺失"
                                            % key)
                                elif len(inf_para) != len(inf_asse):
                                    self.L.debug(
                                        'yaml文件接口:%s interfaceParameters内case数与interfaceAsserts内断言'
                                        '数不相等' % key)
                            elif data_keys[2] != 'interfaceAsserts':
                                self.L.debug(
                                    'yaml文件中接口:%s interfaceAsserts字段缺失' % key)
                        elif data_keys[1] != 'interfaceParameters':
                            self.L.debug(
                                'yaml文件中接口:%s interfaceParameters字段缺失' % key)
                    elif data_keys[0] != 'baseInfo':
                        self.L.debug('yaml文件中接口:%s baseInfo字段缺失' % key)
                elif len(data_keys) != 3:
                    self.L.debug("yaml文件接口:%s 字段错误" % key)
            # 判断解析yaml文件获得的数据是否与检查通过的接口请求数据data_files是否相等,相等,则返回data_file{},
            # 不相等则抛出异常,且不返回data_file{}
            if len(data_file) == len(data_files):
                self.L.info("解析的yaml文件数据放入data_file{}中")
                return data_file
            elif len(data_file) != len(data_files):
                self.L.debug("接口请求缺失")
        except Exception as e:
            self.L.debug('请求异常:%s' % e)
Beispiel #13
0
class KeyFaker(object):
    """
    按指定条件生成随机数据
    """
    def __init__(self):
        self.L = Log("KeyFaker").logger

    def get_some_things(self, faker_type: str = "" or list) -> str or int or float:
        """
        根据faker type生成响应数据,并返回结果
        :param faker_type: mobile, farm, name, shop, int, float
        :return:
        """
        data = ""
        fake = Factory().create('zh_CN')
        # 传入为list时,随机返回list中的一个值
        if isinstance(faker_type, list):
            return random.choice(faker_type)
        elif isinstance(faker_type, str):
            # 若传入时下列关键字,返回对应的值
            record = faker_type.lower()

            if record == 'mobile':
                data = fake.phone_number()
                self.L.info("随机生成手机号:%s" % data)

            elif record == 'farm':
                data = fake.company_prefix() + "的" + fake.name() + "在中国" + fake.city() + "的农场"
                self.L.info("随机生成农场名:%s" % data)

            elif record == 'name':
                data = fake.name()
                self.L.info("随机生成用户民:%s" % data)

            elif record == 'shop':
                data = fake.company()
                self.L.info("随机生成店铺名:%s" % data)

            elif record == 'integer':
                data = random.randint(1, 100)
                self.L.info("随机生成整数:%s" % data)

            elif record == 'decimal':
                data = random.uniform(1, 50)
                self.L.info("随机生成小数:%s" % data)
            elif record == 'text':
                data = (fake.text().replace("\n", " "))[:20]
                self.L.info("随机20位字符串:%s" % data)
            elif record == 'address':
                data = fake.address()
                self.L.info("随机生成地址:%s" % data)
        else:
            data = faker_type
        return data

# if __name__ == '__main__':
#         f = KeyFaker()
#         f.get_some_things('farm')
Beispiel #14
0
 def __init__(self):
     self.L = Log("KeyFaker").logger
Beispiel #15
0
 def __init__(self):
     global global_dict
     self.L = Log("KeyGlobal").logger
Beispiel #16
0
 def __init__(self):
     self.L = Log("KeySquery").logger
Beispiel #17
0
 def __init__(self, file_name: str):
     """
     文件操作类,传入文件地址,将文件读入缓存中备用
     """
     self.L = Log("FileOperation").logger
     self.fileName = file_name
Beispiel #18
0
class Runner(object):
    """
    获取yaml中的请求和断言,并调用Parser进行解析
    """
    def __init__(self):
        self.L = Log("Runner").logger
        self.key = KeyGlobal()
        self.key.set_global_key('data_current', '{}')
        self.key.set_global_key('data_last', '{}')
        self.p = Dispatcher()

    def do_request(self, filename):
        """
        1.按data_file中的接口数量和接口测试次数,组装请求,并检查结果(断言引用Parser进行关键字解析)
        2.需要记录当次测试,执行case的位置,第几个接口第几个步骤,每次执行完成后,将执行时的请求和响应封装到 data_current{}中
        3.将上一次请求的响应和结果封装到 data_last{}中
        4.执行请求前,需要检查请求中是否包含关键字
        :return:
        """
        self.L.critical("进入do_request")
        fop = FileOperation(filename)
        try:
            data_file = fop._format_checker()
        except Exception as e:
            raise Exception('当前文件异常')
        for interface_name in data_file.keys():
            self.L.critical('当前接口名字为: %s' % interface_name)
            data = data_file.get(interface_name)
            self.L.debug('当前接口是否运行: %s' %
                         data.get('baseInfo').get('directExecution'))
            if data.get('baseInfo').get('directExecution') is True or data.get(
                    'baseInfo').get('directExecution') is None:
                self.L.info("当前接口的baseInfo数据存入全局变量baseInfo,值为: %s" %
                            data.get('baseInfo'))
                self.key.set_global_key("baseInfo", data.get('baseInfo'))
                method = data.get('baseInfo').get('requestMethod')
                self.L.debug('当前接口请求方法: %s' % method)
                # 同一个接口在yaml不同层次使用时,用!!!做区分
                self.__choice_request(method, data,
                                      interface_name.split("!!!")[0])

    def __check_resp(self, data, index):
        """
        对一套断言进行解析并断言
        :param data: yaml文件中该接口的所有信息数据
        :param index: 该请求的第几套断言
        :return:
        """

        if data.get('interfaceAsserts')[index] is not None:

            for k, v in data.get('interfaceAsserts')[index].items():

                if isinstance(v, list):
                    if k.find('RECORD') < 0:
                        for j in v:
                            # todo 查找该关键字不做断言需要优化
                            try:
                                self.L.debug('断言是: %s, %s' %
                                             (self.p.key_dispatcher(k),
                                              self.p.key_dispatcher(j)))
                                assert self.p.key_dispatcher(
                                    k) == self.p.key_dispatcher(j)
                            except AssertionError:
                                self.L.error('\n期望值: %s\n返回值: %s' %
                                             (self.p.key_dispatcher(j),
                                              self.p.key_dispatcher(k)))
                    else:
                        self.L.info("该关键字不做断言,数据为 %s       %s:" % (k, v))
                        self.p.key_dispatcher(k, self.p.key_dispatcher(v))
                else:
                    if k.find('RECORD') < 0:
                        # todo 查找该关键字不做断言需要优化
                        try:
                            self.L.debug('断言是: %s, %s' %
                                         (self.p.key_dispatcher(k),
                                          self.p.key_dispatcher(v)))
                            assert self.p.key_dispatcher(
                                k) == self.p.key_dispatcher(v)
                        except AssertionError:
                            self.L.error('\n期望值: %s\n返回值: %s' %
                                         (self.p.key_dispatcher(v),
                                          self.p.key_dispatcher(k)))
                    else:
                        self.L.info("该关键字不做断言,数据为 %s       %s:" % (k, v))
                        self.p.key_dispatcher(k, self.p.key_dispatcher(v))
        else:
            self.L.warning('yaml断言部分为空')

    def __get_data_params(self, index):
        """
        对请求的一套参数进行解析并拼接成dict
        :param index: 该请求的第几套参数
        :return: 返回dict
        """
        data_params = {}
        # try:
        for k, v in index.items():
            if k.find('RECORD') < 0:
                if isinstance(v, dict):
                    v_dict = {}
                    v_list = []
                    flag = 0
                    k = 1
                    for vk, vv in v.items():
                        vv = self.p.key_dispatcher(vv)
                        if isinstance(vv, list):
                            flag = 1
                            if k == 1:
                                for _ in vv:
                                    v_dict = {}
                                    v_list.append(v_dict)
                                k = k + 1
                            for i in range(len(vv)):
                                v_list[i][self.p.key_dispatcher(
                                    vk)] = self.p.key_dispatcher(vv[i])

                        else:
                            flag = 0
                            v_dict[self.p.key_dispatcher(
                                vk)] = self.p.key_dispatcher(vv)
                    if flag == 0:
                        data_params[self.p.key_dispatcher(k)] = v_dict
                    else:
                        data_params[self.p.key_dispatcher(
                            k)] = urllib.parse.quote(str(v_list),
                                                     safe=string.printable)
                else:
                    k = self.p.key_dispatcher(k)
                    v = self.p.key_dispatcher(v)
                    data_params[k] = v
            else:
                self.p.key_dispatcher(k, self.p.key_dispatcher(v))
        # except Exception as e:
        #     self.L.error('解析请求参数错误: %s' % e)
        self.L.debug(data_params)
        return data_params

    def __choice_request(self, method, data, interface_name):
        self.L.debug('当前接口的HOST: %s' %
                     data.get('baseInfo').get('serverAddress'))
        url = data.get('baseInfo').get('serverAddress') + interface_name
        self.L.debug('当前接口的Headers: %s' %
                     data.get('baseInfo').get('requestHeaders'))
        headers = data.get('baseInfo').get('requestHeaders')
        index = 0
        for data_params in data.get('interfaceParameters'):
            self.L.info('当前接口请求解析前的参数: %s' % data_params)
            if data_params is not None:
                data_params = self.__get_data_params(data_params)
                self.L.info('当前接口请求解析后的参数: %s' % data_params)
            else:
                self.L.info('当前接口请求参数不需要解析')
            self.L.debug('写入全局变量data_last: %s' %
                         self.key.get_global_value_by_key('data_current'))
            self.key.set_global_key(
                "data_last",
                "%s" % self.key.get_global_value_by_key('data_current'))
            try:
                self.L.info("--------------------发送请求中--------------------")
                self.L.info("请求URL: %s" % url)
                self.L.info("参数: %s" % data_params)

                if method == 'POSTFILE':
                    file_path = str(list(data_params.values())[0])
                    file_key = list(data_params.keys())[0]
                    file_name = file_path.split("/")[-1:][0]
                    file_bin_data = open(file_path, 'rb')
                    content_type = str(
                        mimetypes.types_map.get(
                            "." + file_path.split(".")[-1:][0], None))
                    files = {
                        file_key: (file_name, file_bin_data, content_type)
                    }
                    resp = requests.post(url=url, files=files)
                elif method == 'GET':
                    resp = requests.get(url=url,
                                        headers=headers,
                                        params=data_params)
                else:
                    resp = requests.post(url,
                                         headers=headers,
                                         data=data_params)
                self.L.info("--------------------请求已完成--------------------")
                self.L.info("请求返回: %s" % resp.text)
                if resp.status_code == 200:
                    try:
                        data_dict = {
                            'req': data_params,
                            'resp': json.loads(resp.text)
                        }
                    except Exception as e:
                        self.L.error(e)
                        data_dict = {'req': data_params, 'resp': resp.text}
                    self.L.debug('data_current: {"req": %s,"resp": %s}' %
                                 (data_params, resp.text))
                    self.key.set_global_key("data_current", data_dict)
                    self.__check_resp(data, index)
                elif str(resp.status_code)[0] == '5':
                    self.L.debug('服务器错误,状态为 %s' % str(resp.status_code))
                elif str(resp.status_code)[0] == '4':
                    self.L.debug('请求错误,状态为 %s' % str(resp.status_code))
                elif str(resp.status_code)[0] == '3':
                    self.L.debug('重定向请求,状态为 %s' % str(resp.status_code))
                else:
                    self.L.debug('不知名错误,状态为 %s' % str(resp.status_code))
            except Exception as e:
                self.L.error('请求异常 %s' % e)
            index += 1
Beispiel #19
0
 def __init__(self):
     """
     解析参数中的key或value信息,并返回各自关键字执行结果
     """
     self.L = Log("Dispatcher").logger
Beispiel #20
0
 def __init__(self):
     self.L = Log("Runner").logger
     self.key = KeyGlobal()
     self.key.set_global_key('data_current', '{}')
     self.key.set_global_key('data_last', '{}')
     self.p = Dispatcher()
Beispiel #21
0
 def __init__(self):
     self.L = Log("ProduceCaseYaml").logger
Beispiel #22
0
class SendRequest(object):
    def __init__(self):
        """
        请求类初始化本类日志
        """
        self.L = Log("SendRequest").logger

    @staticmethod
    def _json_format(data):
        if isinstance(data, str):
            json_str = json.loads(data)
            return json.dumps(json_str,
                              ensure_ascii=False,
                              sort_keys=True,
                              indent=2,
                              separators=(',', ': '))
        elif isinstance(data, dict):
            return json.dumps(data,
                              ensure_ascii=False,
                              sort_keys=True,
                              indent=2,
                              separators=(',', ': '))

    def post(self,
             url: str,
             body: object,
             headers: dict = None,
             cookies=None) -> str:
        """
        发送POST请求
        :param url: 包括请求协议与请求路径的地址
        :param body: 请求报文消息内容
        :param headers: 请求报文头
        :param cookies: 请求cookie
        :return: python3默认为bytes, 统一返回decode之后的str
        """
        client = requests.session()
        response = client.post(url=url,
                               data=body,
                               headers=headers,
                               cookies=cookies).content.decode('utf-8')
        # todo: 暂时未做各响应码的判断
        self.L.debug("请求地址: %s" % url)
        self.L.debug("请求参数:\n%s" % self._json_format(body))
        self.L.debug("响应内容:\n%s" % self._json_format(response))
        return response

    def get(self, url: str, headers: dict = None) -> str:
        """
        发送GET请求
        :param url: 包括请求协议与请求参数的地址
        :param headers: 请求报文头
        :return: python3默认为bytes, 统一返回decode之后的str
        """
        client = requests.session()
        response = client.get(url=url, headers=headers).content.decode('utf-8')
        # todo: 暂时未做各响应码的判断
        self.L.debug("请求地址: %s" % url)
        self.L.debug("响应内容:\n%s" % self._json_format(response))
        return response

    def post_file(self,
                  url: str,
                  file_path: str,
                  file_key: str,
                  data_dict: dict = None) -> str:
        """
        发送POST文件请求
        :param url: 包括请求协议与请求路径的地址
        :param file_path: 文件的全路径
        :param file_key: 传文件的键名
        :param data_dict: 报文消息体内容
        :return: python3默认为bytes, 统一返回decode之后的str
        """
        file_name = file_path.split("/")[-1:][0]
        file_bin_data = open(file_path, 'rb')
        content_type = str(
            mimetypes.types_map.get("." + file_path.split(".")[-1:][0], None))
        encode_file_name = urllib.parse.quote(file_name,
                                              safe='&?=:/',
                                              encoding='UTF-8',
                                              errors=None)
        files = {file_key: (encode_file_name, file_bin_data, content_type)}
        response = requests.post(url=url, data=data_dict,
                                 files=files).content.decode('utf-8')
        # todo: 暂时未做各响应码的判断, 后期优化到post方法中
        self.L.debug("请求地址: %s" % url)
        self.L.debug("文件: %s" % file_path)
        self.L.debug("请求参数:\n%s" % self._json_format(data_dict))
        self.L.debug("响应内容:\n%s" % self._json_format(response))
        return response
 def __init__(self):
     self.iterative_values = False
     self.L = Log("KeyGeneralMethods").logger
Beispiel #24
0
 def __init__(self):
     self.L = Log("KeyResponse").logger
     self.li = []
     self.kg = KeyGlobal()