def check_json(src_data, dst_data, success): """ 校验的json :param src_data: 校验内容 :param dst_data: 接口返回的数据(被校验的内容) :param success: 全局测试结果 :return: """ global result if isinstance(src_data, dict): # 若为dict格式 for key in src_data: if key not in dst_data: success["result"] = False raise failureException("JSON格式校验,关键字 %s 不在返回结果 %s" % (key, dst_data)) else: this_key = key # 递归 if isinstance(src_data[this_key], dict) and isinstance( dst_data[this_key], dict): check_json(src_data[this_key], dst_data[this_key], success) elif isinstance(type(src_data[this_key]), type(dst_data[this_key])): success["result"] = False raise failureException( "JSON格式校验,关键字 %s 与 %s 类型不符" % (src_data[this_key], dst_data[this_key])) else: pass else: success["result"] = False raise failureException("JSON校验内容非dict格式")
def get_time(time_type, layout, unit="0,0,0,0,0"): """ 获取时间 :param time_type: 现在的时间now, 其他时间else_time :param layout: 10timestamp, 13timestamp, else 时间类型 :param unit: 时间单位: [seconds, minutes, hours, days, weeks] 秒,分,时,天,周 :return: """ tim = datetime.datetime.now() if time_type != "now": lag = unit.split(",") try: tim = tim + datetime.timedelta(seconds=int(lag[0]), minutes=int(lag[1]), hours=int(lag[2]), days=int(lag[3]), weeks=int(lag[4])) except ValueError: raise failureException("获取时间错误,时间单位%s" % unit) # 获取10位时间戳 if layout == "10timestamp": tim = tim.strftime('%Y-%m-%d %H:%M:%S') tim = int(time.mktime(time.strptime(tim, "%Y-%m-%d %H:%M:%S"))) return tim # 获取13位时间戳 elif layout == "13timestamp": tim = tim.strftime('%Y-%m-%d %H:%M:%S') tim = int(time.mktime(time.strptime(tim, "%Y-%m-%d %H:%M:%S"))) tim = int(round(tim * 1000)) return tim # 按传入格式获取时间 else: tim = tim.strftime(layout) return tim
def read_json(test_name, code_json, relevance, _path, result): """ 校验内容读取 :param test_name: 用例名称,用作索引 :param code_json: 文件路径 :param relevance: 关联对象 :param _path: case路径 :param result: 全局结果 :return: """ # 用例中参数为json格式 if isinstance(code_json, dict): code_json = manage(code_json, relevance) # 用例中参数非json格式 else: try: with open(_path + "/" + code_json, "r", encoding="utf-8") as f: data = json.load(f) for i in data: # 遍历,通过用例名称做索引查找到第一个期望结果后,跳出循环 if i["test_name"] == test_name: code_json = i["json"] break # 如果code_json为空,表示未找到用例关联的期望结果 if not code_json: result["result"] = False raise failureException("未找到用例关联的期望结果\n文件路径: %s\n索引: %s" % (code_json, test_name)) else: code_json = manage(code_json, relevance) # 文件不存在 except FileNotFoundError: result["result"] = False raise failureException("用例关联文件不存在\n文件路径: %s" % code_json) # 文件存在,但里面存储的数据有误,json.load执行异常 except JSONDecodeError: result["result"] = False raise failureException("用例关联的期望文件有误\n文件路径: %s" % code_json) # 返回获取的期望结果 return code_json
def random_string(num_length): """ 从a-zA-Z0-9生成指定数量的随机字符 :param num_length: 字符串长度 :return: """ try: num_length = int(num_length) except ValueError: raise failureException("从a-zA-Z0-9生成指定数量的随机字符失败!长度参数有误 %s" % num_length) num = ''.join( random.sample(string.ascii_letters + string.digits, num_length)) return num
def read_param(test_name, param, relevance, _path, result): """ 判断用例中参数类型 :param test_name: 用例名称 :param param: :param relevance: 关联对象 :param _path: case路径 :param result: 全局结果 :return: """ # 用例中参数为json格式 if isinstance(param, dict): param = manage(param, relevance) # 用例中参数非json格式 else: try: with open(_path + "/" + param, "r", encoding="utf-8") as f: data = json.load(f) for i in data: # 通过test_name索引,提取第一个匹配到的用例参数 if i["test_name"] == test_name: param = i["parameter"] break # 为空,未匹配到 if not isinstance(param, dict): result["result"] = False raise failureException("未找到用例关联的参数\n文件路径: %s\n索引: %s" % (param, test_name)) else: param = manage(param, relevance) except FileNotFoundError: result["result"] = False raise failureException("用例关联文件不存在\n文件路径: %s" % param) except JSONDecodeError: result["result"] = False raise failureException("用例关联的参数文件有误\n文件路径: %s" % param) return param
def random_int(scope): """ 获取随机整型数据 :param scope: 时间范围 :return: """ try: start_num, end_num = scope.split(",") start_num = int(start_num) end_num = int(end_num) except ValueError: raise failureException("调用随机整数失败,范围参数有误!\n %s" % str(scope)) if start_num <= end_num: num = random.randint(start_num, end_num) else: num = random.randint(end_num, start_num) return num
def ini_request(case_dict, relevance, _path, result): """ 用例前提条件执行,提取关联键 :param case_dict: 用例对象 :param relevance: 关联对象 :param _path: case路径 :param result: 全局结果 :return: """ if isinstance(case_dict["premise"], list): logging.info("执行测试用例前置接口") with allure.step("接口关联请求"): for i in case_dict["premise"]: relevance_list = relevance.copy() for j in range(0, 3): # 获取前置接口关联数据失败 code, data = send_request( i, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), relevance_list, _path, result) if not data: with allure.step("接口请求失败!等待三秒后重试!"): pass logging.info("接口请求失败!等待三秒后重试!") continue if i["relevance"]: if len(i["relevance"]): relevance = get_relevance(data, i["relevance"], relevance) if isinstance(relevance, bool): with allure.step("从结果中提取关联键的值失败!等待3秒后重试!"): pass logging.info("从结果中提取关联键的值失败!等待3秒后重试!") time.sleep(3) continue else: break else: break else: break if isinstance(relevance, bool): logging.info("从结果中提取关联键的值失败!重试三次失败") result["result"] = False raise failureException("获取前置接口关联数据失败") return relevance
def random_float(data): """ 获取随机整型数据 :param data: :return: """ try: start_num, end_num, accuracy = data.split(",") start_num = int(start_num) end_num = int(end_num) accuracy = int(accuracy) except ValueError: raise failureException("调用随机整数失败,范围参数或精度有误!\n小数范围精度 %s" % data) if start_num <= end_num: num = random.uniform(start_num, end_num) else: num = random.uniform(end_num, start_num) num = round(num, accuracy) return num
def check(test_name, case_data, code, data, relevance, _path, success): """ 校验测试结果 :param test_name: 测试用例 :param case_data: 测试用例 :param code: HTTP状态 :param data: 返回的接口json数据 :param relevance: 关联值对象 :param _path: case路径 :param success: 全局测试结果 :return: """ # 不校验 if case_data["check_type"] == 'no_check': with allure.step("不校验结果"): pass # 校验json格式 elif case_data["check_type"] == 'json': expected_request = case_data["expected_request"] # 判断预期结果格式,如果是字符串,则打开文件路径,提取保存在文件中的期望结果 if isinstance(case_data["expected_request"], str): expected_request = expectedManage.read_json( test_name, expected_request, relevance, _path, success) with allure.step("JSON格式校验"): allure.attach("期望code", str(case_data["expected_code"])) allure.attach('期望data', str(expected_request)) allure.attach("实际code", str(code)) allure.attach('实际data', str(data)) if int(code) == case_data["expected_code"]: if not data: data = "{}" # json校验 CheckJson.check_json(expected_request, data, success) else: success["result"] = False if case_data.get("CustomFail"): info = CustomFail.custom_manage(case_data.get("CustomFail"), relevance) raise failureException( str(info) + "\nhttp状态码错误!\n %s != %s" % (code, case_data["expected_code"])) else: raise failureException("http状态码错误!\n %s != %s" % (code, case_data["expected_code"])) # 只校验HTTP状态 elif case_data["check_type"] == 'only_check_status': with allure.step("校验HTTP状态"): allure.attach("期望code", str(case_data["expected_code"])) allure.attach("实际code", str(code)) if int(code) == case_data["expected_code"]: pass else: success["result"] = False if case_data.get("CustomFail"): info = CustomFail.custom_manage(case_data.get("CustomFail"), relevance) raise failureException( str(info) + "\nhttp状态码错误!\n %s != %s" % (code, case_data["expected_code"])) else: raise failureException("http状态码错误!\n %s != %s" % (code, case_data["expected_code"])) # 完全校验 elif case_data["check_type"] == 'entirely_check': expected_request = case_data["expected_request"] # 判断预期结果格式,如果是字符串,则打开文件路径,提取保存在文件中的期望结果 if isinstance(case_data["expected_request"], str): expected_request = expectedManage.read_json( test_name, expected_request, relevance, _path, success) with allure.step("完全校验"): allure.attach("期望code", str(case_data["expected_code"])) allure.attach('期望data', str(expected_request)) allure.attach("实际code", str(code)) allure.attach('实际data', str(data)) if int(code) == case_data["expected_code"]: result = operator.eq(expected_request, data) if result: pass else: success["result"] = False if case_data.get("CustomFail"): info = CustomFail.custom_manage( case_data.get("CustomFail"), relevance) raise failureException( str(info) + "\n完全校验失败! %s ! = %s" % (expected_request, data)) else: raise failureException("完全校验失败! %s ! = %s" % (expected_request, data)) else: success["result"] = False raise failureException("http状态码错误!\n %s != %s" % (code, case_data["expected_code"])) # 正则校验 elif case_data["check_type"] == 'Regular_check': if int(code) == case_data["expected_code"]: try: result = "" # 初始化校验内容 if isinstance(case_data["expected_request"], list): # 多个正则表达式校验,遍历校验 for i in case_data["expected_request"]: result = re.findall(i.replace("\"", "\'"), str(data)) allure.attach('校验完成结果\n', str(result)) else: # 单个正则表达式 result = re.findall( case_data["expected_request"].replace("\"", "\'"), str(data)) with allure.step("正则校验"): allure.attach("期望code", str(case_data["expected_code"])) allure.attach( '正则表达式', str(case_data["expected_request"]).replace( "\'", "\"")) allure.attach("实际code", str(code)) allure.attach('实际data', str(data)) allure.attach( case_data["expected_request"].replace("\"", "\'") + '校验完成结果', str(result).replace("\'", "\"")) # 未匹配到校验内容 if not result: success["result"] = False if case_data.get("CustomFail"): info = CustomFail.custom_manage( case_data.get("CustomFail"), relevance) raise failureException( str(info) + "\n正则未校验到内容! %s" % case_data["expected_request"]) else: raise failureException("正则未校验到内容! %s" % case_data["expected_request"]) # 正则表达式为空时 except KeyError: success["result"] = False raise failureException("正则校验执行失败! %s\n正则表达式为空时" % case_data["expected_request"]) else: success["result"] = False raise failureException("http状态码错误!\n %s != %s" % (code, case_data["expected_code"])) # 数据库校验 elif case_data["check_type"] == "datebase_check": pass else: success["result"] = False raise failureException("无该校验方式%s" % case_data["check_type"])
def send_request(data, host, address, relevance, _path, success): """ 再次封装请求 :param data: 测试用例 :param host: 测试地址 :param address: 接口地址 :param relevance: 关联对象 :param _path: case路径 :param success: 全局结果 :return: """ logging.info("=" * 100) header = ReadParam.read_param(data["test_name"], data["headers"], relevance, _path, success) # 处理请求头 logging.debug("请求头处理结果: %s" % header) parameter = ReadParam.read_param(data["test_name"], data["parameter"], relevance, _path, success) # 处理请求参数 logging.debug("请求参数处理结果: %s" % header) try: # 如果用例中写了host和address,则使用用例中的host和address,若没有则使用全局的 host = data["host"] except KeyError: pass try: address = data["address"] except KeyError: pass host = HostManage.host_manage(host) # host处理,读取配置文件中的host address = ParamManage.manage(address, relevance) logging.debug("host处理结果: %s" % host) if not host: raise failureException("接口请求地址为空 %s" % data["headers"]) logging.info("请求接口:%s" % str(data["test_name"])) logging.info("请求地址:%s" % data["http_type"] + "://" + host + address) logging.info("请求头: %s" % str(header)) logging.info("请求参数: %s" % str(parameter)) if data["request_type"].lower() == 'post': if data["file"]: with allure.step("POST上传文件"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) result = confighttp.post( header=header, address=data["http_type"] + "://" + host + address, request_parameter_type=data["parameter_type"], files=parameter, timeout=data["timeout"]) else: with allure.step("POST请求接口"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) logging.info("POST请求接口") result = confighttp.post( header=header, address=data["http_type"] + "://" + host + address, request_parameter_type=data["parameter_type"], data=parameter, timeout=data["timeout"]) elif data["request_type"].lower() == 'get': with allure.step("GET请求接口"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) logging.info("GET请求接口") result = confighttp.get(header=header, address=data["http_type"] + "://" + host + address, data=parameter, timeout=data["timeout"]) elif data["request_type"].lower() == "put": if data["file"]: with allure.step("PUT上传文件"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) logging.info("PUT上传文件") result = confighttp.put( header=header, address=data["http_type"] + "://" + host + address, request_parameter_type=data["parameter_type"], files=parameter, timeout=data["timeout"]) else: with allure.step("PUT请求接口"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) logging.info("PUT请求接口") result = confighttp.put( header=header, address=data["http_type"] + "://" + host + address, request_parameter_type=data["parameter_type"], data=parameter, timeout=data["timeout"]) elif data["request_type"].lower() == "delete": with allure.step("DELETE请求接口"): allure.attach("请求接口:", str(data["test_name"])) allure.attach("请求地址", data["http_type"] + "://" + host + address) allure.attach("请求头", str(header)) allure.attach("请求参数", str(parameter)) logging.info("DELETE请求接口") result = confighttp.delete(header=header, address=data["http_type"] + "://" + host + address, data=parameter, timeout=data["timeout"]) else: result = {"code": False, "data": False} logging.info("接口请求结果:\n %s" % str(result)) return result