python实战-基于正交实验(工具:allpairs)自动生成接口异常测试用例

目前支持的功能

1.基于不同的参数类型(str、int、float、bool、list、tuple、dict、set、None、date、datetime、time、timestamp)自动生成正交测试用例
2.可以自定义参数长度与内容,方便覆盖边界值测试
3.提供自定义过滤参数组合的入口,方便自定义

实现思路

1.抓取api信息(目前公司用的swagger): https://www.cnblogs.com/qtclm/p/17049176.html ,uri、method、params、response,解析完成后写入excle
2.读取抓取完毕的api信息,处理为allpairs所需要的ordereddict
3.调用allpairs工具生成测试用例
4.解析allpairs生成的测试用例(输出为字符串),并处理为dict
5.处理完毕后写入excel

后期优化

1.根据接口响应实现自动断言
2.增加其他接口平台的api抓取(openapi、eolink等)
3.增加其他自动化生成用例的方法(有效、无效等价类,流量回放等)
4.集成到平台

遇到的问题

1.allpairs只支持两个以上的参数生成,因为参数只有一个时,需要自行处理
2.参数为json嵌套时,allpairs输出的参数需要额外特殊处理,这块也是最麻烦的地方
3.可变类型在循环过程中尽量使用深拷贝对象,避免循环运行中被意外修改
4.类变量、实例变量需要合理运用,例如循环时需要合理的进行初始化

# _*_ coding: UTF-8 _*_ """ @project -> file : city-test -> rr @Author          : qinmin.vendor @Date            : 2023/1/29 19:44 @Desc            : 自动生成接口测试用例:支持正交实验,等价类,边界值 """  import copy import json import os import random import re import sys from collections import OrderedDict from allpairspy import AllPairs from utils.operation_datas import operationExcle import math from utils.time_utils import timeUtil from utils.wrapper_util import exec_time_wrapper from inspect import isfunction  from faker import Faker '''faker使用教程:https://blog.csdn.net/qq_42412061/article/details/122997802'''  class autoGenrateApiCaseAllpairspy(object):      time_util = timeUtil()     fake = Faker(locale="zh_cn")  # 指定语言为中文      CONST_MAX_STRING_LENGTH = 100     CONST_MIN_STRING_LENGTH = 1     # 生成字符串相关的数据     # special_chars是否包含特殊字符;digits是否包含数字;upper_case是否包含大写字母,lower_case是否包含小写字母     special_character = fake.password(length=8, special_chars=True, digits=False, upper_case=False,                                       lower_case=False)  # 生成随机特殊字符     random_str = fake.paragraph()  # 生成随机字符     random_str_max = random_str * math.ceil(CONST_MAX_STRING_LENGTH / len(random_str))     phone_number = fake.phone_number()  # 生成随机电话号码      # 生成时间相关的数据     random_date = fake.date(pattern="%Y-%m-%d", end_datetime=None)  # 生成随机日期     random_start_datetime = time_util.adjust_time(num=-30)     random_end_datetime = time_util.adjust_time(num=0)     random_start_timestamp_millisecond = time_util.adjust_time(num=-30, is_timestamp=True, millisecond=True)     random_end_timestamp_millisecond = time_util.adjust_time(num=0, is_timestamp=True, millisecond=True)     random_start_timestamp = time_util.adjust_time(num=-30, is_timestamp=True, millisecond=False)     random_end_timestamp = time_util.adjust_time(num=0, is_timestamp=True, millisecond=False)      # 生成int与float相关的数据     random_int = random.randint(1, 100)     random_float = round(random.random(), 6) + random_int  # 生成随机字符     random_int_max = str(random_int) * math.ceil(CONST_MAX_STRING_LENGTH / len(str(random_int)))     random_float_max = str(str(random_float) *         math.ceil(CONST_MAX_STRING_LENGTH / len(str(random_float).replace('.', '')))).        replace('.','') + "." + str(random_int)       STRING_ENUM = ["", None, random_str, special_character,                    random_str_max[:CONST_MAX_STRING_LENGTH], random_str[:CONST_MIN_STRING_LENGTH],                    random_start_datetime, random_end_datetime, random_date]      INT_FLOAT_ENUM = [0, None, special_character, random_int, random_float,                       int(random_int_max[:CONST_MAX_STRING_LENGTH]),                       int(str(random_int)[:CONST_MIN_STRING_LENGTH]), int(random_float_max[:CONST_MAX_STRING_LENGTH]),                       int(str(random_float)[:CONST_MIN_STRING_LENGTH]), random_start_timestamp,                       random_start_timestamp_millisecond, random_end_timestamp, random_end_timestamp_millisecond]     LIST_ENUM=[[], None, [{}]]     BOOL_ENUM=[None, False, True,"true","false"]     OBJECT_ENUM=[None,{}]     NULL_ENUM=[None,"null"]      # 定义接口字段生成的类型与枚举     CONST_TYPE_ENUM = {         str: STRING_ENUM,"string": STRING_ENUM,         int: INT_FLOAT_ENUM,"integer": INT_FLOAT_ENUM,"number": INT_FLOAT_ENUM,         None: NULL_ENUM, "NONE": NULL_ENUM,"null": NULL_ENUM,         float: INT_FLOAT_ENUM,"double": INT_FLOAT_ENUM,         bool: BOOL_ENUM,'bool': BOOL_ENUM,"boolean": BOOL_ENUM,         dict: OBJECT_ENUM,'object': OBJECT_ENUM,set: LIST_ENUM,list: LIST_ENUM,'array': LIST_ENUM,     }      CONST_TYPE_ENUM_COPY = copy.deepcopy(CONST_TYPE_ENUM)      is_array = False #判断参数传入的参数是不是list      params_key_list = [] #判断参数的key对应的value是不是list类型,如果是,就将key存进此对象     extra_cases = [] #存放额外的case,请求参数中的key嵌套json的情况      excle_path = './'     excle_name_params_field_detail = 'auto_genrate_api_case_allpairspy_params_field_detail.xlsx'     excle_name_params_obj = 'auto_genrate_api_case_allpairspy_params_obj_5.xlsx'     # excle_name_cases_data = 'maint-api.xlsx'     excle_name_cases_data = 'maint-apiv2-api-docs.xlsx'      # 递归解析json,原文:https://blog.csdn.net/qq_45662588/article/details/122265447     read_excle_case_field_desc={'case':0,'uri':1,'method':2,"params_path":3,"params_body":5,"response_body":7,"skip":9}     # 数据处理前的case表头,写入excle中最终会删除params_path,且params_body替换为params && response_body替换为expected     write_excle_case_field_desc={'case':0,'uri':1,'method':2,'params_path':3,'params_body':4,'response_body':5,'skip':6}      @classmethod     def custom_valid_combination(cls,row):         """         自定义过滤条件,返回false的条件不会出现在组合中         """         n = len(row)         if n > 1:             if row[0] in (None,'',""):                 return False         return True      # 指定:自定义过滤函数     all_pairs_filter_func=custom_valid_combination     if not (isfunction(all_pairs_filter_func) or isinstance(all_pairs_filter_func,(classmethod,staticmethod))) :         raise Exception(f"all_pairs_filter_func对象必须是一个方法:{all_pairs_filter_func}")      @classmethod     def read_all_cases_data(cls):         cases_data_obj=operationExcle(excle_path=cls.excle_path,excle_name=cls.excle_name_cases_data)         lines=cases_data_obj.get_lines()+1         case_list=[]         for i in range(lines):             # yield cases_data_obj.get_row_data(i+1)             values=cases_data_obj.get_row_data(i+1)             out_values=[]             for i in cls.read_excle_case_field_desc:                 out_values.append(values[cls.read_excle_case_field_desc[i]])             if out_values[0] is not None:                 case_list.append(out_values)         return case_list      @classmethod     def dict_parse_generator(cls,params,pre=None):         '''递归解析json,如果key为对应的值是list且list中的元素不是dict,则不返回'''         pre = pre[:] if pre else []  # 纪录value对应的key信息         # print("params:",params)         if isinstance(params,list) :             params=params[0]         if isinstance(params, dict):             for key, value in params.items():                 if isinstance(value, dict):                     if len(value) > 0:                         for d in cls.dict_parse_generator(value, pre + [key]):                             yield d                     else:                         yield pre + [key, '{}']                 elif isinstance(value, (list, tuple)):                     if len(value) > 0:                         for index, v in enumerate(value):                             # 纪录list的下标与key,方便动态提取                             # print("index",index)                             for d in cls.dict_parse_generator(v, pre + [key, str(index)]):                                 yield d                     else:                         yield pre + [key, '[]'] if isinstance(value,list) else pre + [key,'()']                  else:                     yield pre + [key, value]      @classmethod     def api_prams_convert(cls, params_info):         '''根据参数与参数类型转换为预期定义的数据类型定义的枚举'''          def get_params_field_type(params_field_value):             if str(params_field_value).startswith('"') and str(params_field_value).endswith('"'):                 _type = 'string' or 'str'             elif str(params_field_value).startswith('{') and str(params_field_value).endswith("}"):                 _type = 'object' or 'dict'             elif str(params_field_value).startswith('[') and str(params_field_value).endswith(']'):                 _type = 'array' or 'list'             elif str(params_field_value) in ('0', '0.0'):                 _type = 'number' or 'int'             elif str(params_field_value) in ("true", 'false', 'True', 'False'):                 _type = 'boolean' or 'bool'             elif str(params_field_value) in ('None', 'null', 'nil'):                 _type = 'null' or 'None'             else:                 _type = 'string' or 'str'             return _type          def replace_params_values(params_info):             '''替换参数所有key的内容'''             parse_params_info = list(cls.dict_parse_generator(params_info))             parse_params_info_keys=[i[0] for i in parse_params_info]             # 将没有输出的key添加到字典             for params_info_key in params_info:                 if params_info_key not in parse_params_info_keys:                     parse_params_info.append([params_info_key,params_info[params_info_key]])             for i in range(len(parse_params_info)):                 if parse_params_info[i] :                     params_key = parse_params_info[i][:-1]                         # 组装json提取表达式                     params_extract_str = "']['".join(params_key)                     params_extract_str = "['" + params_extract_str + "']"                     params_extract_str_re = re.search("['d+']", params_extract_str)                     if params_extract_str_re:                         # 去除list索引下标的字符串,处理为eval能够识别的int字符串                         params_extract_str_re = params_extract_str_re.group()                         params_extract_str = params_extract_str.replace(params_extract_str_re,                                             params_extract_str_re.replace("'",'').replace('"',""))                     # 获取key内容                     params_field_value=eval(f"params_info{params_extract_str}")                     params_type=get_params_field_type(params_field_value=params_field_value)                     # # 将不为空得参数值且不在枚举定义范围内的数据添加到枚举定义中,避免影响原有数据且用于完善参数覆盖情况                     if params_field_value and (params_field_value not in cls.CONST_TYPE_ENUM[params_type]):                         cls.CONST_TYPE_ENUM[params_type].append(params_field_value)                      #动态执行代码:替换key的内容                     exec(f"params_info{params_extract_str}={cls.CONST_TYPE_ENUM[params_type]}")          def append_params_key_is_object_to_params_key_list(params_info):             '''追加参数key对应的值是object类型的key到指定list中'''             if isinstance(params_info,list):                 params_info=params_info[0]              for i in params_info:                 if isinstance(params_info[i],list) and isinstance(params_info[i][0],dict)                         and (i not in cls.params_key_list):                     cls.params_key_list.append(i)          if not params_info:             return params_info         if isinstance(params_info, (list, dict)):             if isinstance(params_info, list):                 if params_info:                     params_info = params_info[0]                 cls.is_array = True         replace_params_values(params_info)         append_params_key_is_object_to_params_key_list(params_info)         return params_info      @classmethod     def parse_uri_params_path_query(cls,uri: str, params_path: dict):         '''解析url中的params_path与params_query参数'''         if not params_path:             return {},{}         uri_split = uri.split('/')         uri_params = [i for i in uri_split if i.startswith('{') and i.endswith('}')]         params_path_keys = list(params_path.keys())         uri_params_path_dict = {}  # 存储:uri中的参数是key的情况         uri_params_query_dict = {}  # 存储:uri中的参数不是key的情况,代表是query参数         for params_path_key in params_path_keys:             if "{" + params_path_key + "}" in uri_params:                 uri_params_path_dict[params_path_key]=params_path[params_path_key]             else:                 uri_params_query_dict[params_path_key]=params_path[params_path_key]         return uri_params_path_dict,uri_params_query_dict      @classmethod     def join_request_uri(cls,uri,path_dict,query_dict):         def out_path_replace_uri(uri,dict_obj):             '''uri拼接替换后的path参数'''             if dict_obj:                 for i in dict_obj:                     uri = uri.replace("{" + i + "}",str(dict_obj[i]) )                 return uri             return uri         def out_query_replace_uri(uri,dict_obj):             '''uri拼接替换后的query参数'''             if dict_obj:                 uri += "?"                 for i in dict_obj:                     uri += f"{i}={str(dict_obj[i])}&"                 uri = uri[:-1] if uri[-1] == "&" else uri             return uri          if not (path_dict or query_dict):             return uri         uri=out_path_replace_uri(uri=uri,dict_obj=path_dict)         uri=out_query_replace_uri(uri=uri,dict_obj=query_dict)         uri = cls.time_util.pyobject_to_json_str(uri)         return uri      @classmethod     def out_target_case(cls,src_obj_index, params_all_obj):         '''根据index返回符合条件的case'''         if not params_all_obj:             return {}         _l = len(params_all_obj) - 1         if src_obj_index > _l:             target_case = params_all_obj[random.randint(0, _l)]         else:             target_case = params_all_obj[src_obj_index]         return target_case      @classmethod     @exec_time_wrapper(round_num=10,module_obj=__file__,class_obj=sys._getframe().f_code.co_name,is_send_email=False)     def generate_all_cases(cls, ordered_dict_obj,params_info):          def convert_allpairs_cases_to_cases(params_keys,ordered_dict_obj,cases_obj):             '''将allparis输出的case字符串转换为dict输出'''             if len(params_keys)>=2:                 cls.time_util.append_params_key_isobject_to_extra_cases(case_params_key_obj=ordered_dict_obj,                     params_keys=params_keys,extra_cases=cls.extra_cases,filter_func=cls.all_pairs_filter_func,                     cases_obj=cases_obj,is_append_extra_cases=False,params_key="")             else:                 '''params只有一个key时,直接组装字典输出(allpairs这种情况处理会输出空)'''                 cases = ordered_dict_obj                 for case in cases:                     for case_key in cases[case]:                         cases_obj.append({case: case_key})          def append_extra_case_to_case(cases_obj,extra_cases,params_key_list):             # 将extra_case数据追加到参数中             for index,out_case in enumerate(cases_obj):                 for params_key in params_key_list:                     update_cases=[i for i in extra_cases for o in i if o == params_key]                     extra_case=cls.out_target_case(src_obj_index=index,params_all_obj=update_cases)                     out_case.update(extra_case)          def return_out_cases(params_info,ordered_dict_obj):             '''输出最终转换完成的测试用例集合'''             if isinstance(params_info,list):                 params_info=params_info[0]             params_keys=[i for i in params_info]             out_cases = []             '''将allparis输出的case字符串转换为dict输出'''             convert_allpairs_cases_to_cases(params_keys=params_keys,ordered_dict_obj=ordered_dict_obj,cases_obj=out_cases)             '''将extra_case数据追加到参数中'''             append_extra_case_to_case(cases_obj=out_cases,extra_cases=cls.extra_cases,params_key_list=cls.params_key_list)             return out_cases          if not (params_info or ordered_dict_obj):             return []         return return_out_cases(params_info=params_info,ordered_dict_obj=ordered_dict_obj)      @classmethod     def rm_old_excel(cls, excle_path='./', excle_name=''):         if os.path.exists(os.path.join(excle_path, excle_name)):             os.remove(os.path.join(excle_path, excle_name))      @classmethod     def reset_params_key_list_and_extra_cases(cls):         '''每个api的参数不同,在写入后需要调用此方法重置,避免元素被重复使用'''         cls.params_key_list=[]         cls.extra_cases=[]         # 还原默认的枚举定义,避免数据一直递增         cls.CONST_TYPE_ENUM=cls.CONST_TYPE_ENUM_COPY         cls.is_array=False      @classmethod     def write_params_filed_detail_to_excle(cls, params,ex_obj:operationExcle=None):         '''将参数字段明细写入到excle'''         ex_obj_cp=copy.deepcopy(ex_obj)         if ex_obj is None:             cls.rm_old_excel(excle_path=cls.excle_path, excle_name=cls.excle_name_params_field_detail)             ex_obj = operationExcle(excle_path=cls.excle_path, excle_name=cls.excle_name_params_field_detail)         if not isinstance(ex_obj,operationExcle):             raise Exception(f"传入的对象预期是:{type(operationExcle)},实际为:{type(ex_obj)}")         # print("params:",params)         if isinstance(params,dict):             params=[params]         ordered_dict_obj = cls.api_prams_convert(params)         params_all = cls.generate_all_cases(ordered_dict_obj, params)         for case in params_all:             for case_key in case:                 # 如果key存在与list中,说明参数是list,将object转换为array                 if case_key in cls.params_key_list:                     case[case_key] = [case[case_key]]             ex_obj.write_values([str(i) for i in case.values()])         # 重置参数状态         cls.reset_params_key_list_and_extra_cases()         if ex_obj_cp is None:             ex_obj.write_values(list(params_all[0].keys()))             ex_obj.save_workbook()      @classmethod     def write_cases_obj_to_excle(cls, case_info, params_path,params_body,ex_obj:operationExcle=None):         def write_cases_data_main(case_info,params_all_cases,is_body=False):             '''             将生成完毕的测试用例写入到excel,基础方法(将测试用例明细写入到excle)             Args:                 case_info: 原始的测试用例信息                 params_all_cases: 使用正交生成后的所有测试用例集合                 is_body: 用于区分请求参数是否是body,如果不是bodu,则设置params_bodu为{},因为path与query类型不需要body请求,参数直接拼接到url上了             Returns:             '''             for index, case in enumerate(params_all_cases):                 # print("params_all_cases:",id(params_all_cases))                 path_dict = cls.out_target_case(src_obj_index=index,                                                 params_all_obj=params_all_path) if params_all_path else {}                 query_dict = cls.out_target_case(src_obj_index=index,                                                  params_all_obj=params_all_query) if params_all_query else {}                 # 拼接uri                 uri = cls.join_request_uri(uri=uri_copy, path_dict=path_dict, query_dict=query_dict)                 # print("path_dict:",path_dict)                 # print("query_dict:",query_dict)                 # # 忽略存在参数为空字符的uri                 # if '//' in uri:                 #     continue                 case_identifying_str = '-接口异常测试用例(基于正交实验自动生成)'                 case_name = case_info[cls.write_excle_case_field_desc['case']]                 # 拼接测试用例名称                 if case_identifying_str in case_name:                     case_name = case_name[:case_name.find(case_identifying_str)]                 case_name = case_name + case_identifying_str + '-' + str(index + 1)                 case_info[cls.write_excle_case_field_desc['case']] = case_name                 case_info[cls.write_excle_case_field_desc['uri']] = uri                  for case_key in case:                     # 如果key存在与list中,说明参数是list,将object转换为array                     if case_key in cls.params_key_list:                         case[case_key] = [case[case_key]]                 # print("case:",case)                 # 判断最外层的参数是不是list,是list,将object转换为array                 if cls.is_array:                     case_info[cls.write_excle_case_field_desc['params_body']] = json.dumps([case], ensure_ascii=False)                 else:                     case_info[cls.write_excle_case_field_desc['params_body']] = json.dumps(case, ensure_ascii=False)                 if not is_body:                     # 从params_body中删除params_path&params_query对应的key                     case_info[cls.write_excle_case_field_desc['params_body']] = json.dumps({})                 ex_obj.write_values(case_info)          # ex_obj_cp=copy.deepcopy(ex_obj)         if ex_obj is None:             cls.rm_old_excel(excle_path=cls.excle_path, excle_name=cls.excle_name_params_obj)             ex_obj = operationExcle(excle_path=cls.excle_path, excle_name=cls.excle_name_params_obj)         if not isinstance(ex_obj,operationExcle):             raise Exception(f"传入的对象预期是:{type(operationExcle)},实际为:{type(ex_obj)}")         uri=case_info[cls.write_excle_case_field_desc['uri']]         uri_copy=copy.deepcopy(uri)         # 根据params_path对象区分uri_path参数、uri_query参数         uri_params_path_dict,uri_params_query_dict=cls.parse_uri_params_path_query(uri=uri_copy,params_path=params_path)         # 输出path与body的ordered_dict对象         ordered_dict_obj_path = cls.api_prams_convert(uri_params_path_dict)         ordered_dict_obj_query = cls.api_prams_convert(uri_params_query_dict)         # 输出path与body所有的正交测试用例         params_all_path = cls.generate_all_cases(ordered_dict_obj_path, uri_params_path_dict)         params_all_query = cls.generate_all_cases(ordered_dict_obj_query, uri_params_query_dict)         ordered_dict_obj_body = cls.api_prams_convert(params_body)         params_all_body = cls.generate_all_cases(ordered_dict_obj_body, params_body)          if params_all_body:             write_cases_data_main(case_info=case_info,params_all_cases=params_all_body,is_body=True)         elif params_all_path:             write_cases_data_main(case_info=case_info, params_all_cases=params_all_path, is_body=False)         elif params_all_query:             write_cases_data_main(case_info=case_info, params_all_cases=params_all_query, is_body=False)          # 重置参数状态         cls.reset_params_key_list_and_extra_cases()      @classmethod     @exec_time_wrapper(round_num=10,module_obj=__file__,class_obj=sys._getframe().f_code.co_name,is_send_email=True)     def batch_write_params_filed_detail_to_excle(cls,case_list=None):         if case_list is None:             case_list=cls.read_all_cases_data()         cls.rm_old_excel(excle_path=cls.excle_path, excle_name=cls.excle_name_params_field_detail)         ex_obj = operationExcle(excle_path=cls.excle_path, excle_name=cls.excle_name_params_field_detail)         if isinstance(case_list,dict):             case_list=[case_list]          # 写入首行数据         for params in case_list[1:]:             # params是一个可变类型,程序执行中共用了此对象,这里需要传一个深拷贝对象给他,避免执行过程中params被替换             params=copy.deepcopy(params)             params_body=params[cls.write_excle_case_field_desc['params_body']]             sheet_name=params[cls.write_excle_case_field_desc['case']][:31]             sheet_name=cls.time_util.check_filename(sheet_name,priority_matching_chars=[':','/','\','?','*','[',']'])             # print("sheet_name:",sheet_name)             ex_obj.create_sheet(sheet_name)             ex_obj.data=ex_obj.get_data_for_sheet_name(sheet_name)             if not isinstance(params_body, dict):                 params_body = json.loads(params_body)             if isinstance(params_body,list):                 params_body=params_body[0]             ex_obj.write_values(list(params_body.keys()))             cls.write_params_filed_detail_to_excle(params=params_body,ex_obj=ex_obj)         # 删除默认创建的sheet         ex_obj.delete_sheet(sheet_name='Sheet')         ex_obj.save_workbook()      @classmethod     @exec_time_wrapper(round_num=10,module_obj=__file__,class_obj=sys._getframe().f_code.co_name,is_send_email=False)     def batch_write_cases_obj_to_excle(cls,case_info=None,case_list=None):         if case_list is None:             case_list=cls.read_all_cases_data()         if isinstance(case_list, dict):             case_list = [case_list]         case_info_first_line=case_info         if case_info is None:             case_info_first_line=list(cls.write_excle_case_field_desc.keys())             # 删除params_path, 且params_body替换为params & & response_body替换为expected             case_info_first_line[cls.write_excle_case_field_desc['params_body']]='params'             case_info_first_line[cls.write_excle_case_field_desc['response_body']]='expected'         # 删除旧的文件         cls.rm_old_excel(excle_path=cls.excle_path, excle_name=cls.excle_name_params_obj)         ex_obj = operationExcle(excle_path=cls.excle_path, excle_name=cls.excle_name_params_obj)         ex_obj.write_values(case_info_first_line)         for case in case_list[1:]:             # params是一个可变类型,程序执行中共用了此对象,这里需要传一个深拷贝对象给他,避免执行过程中params被替换             case_info=copy.deepcopy(case)             # if case_info[1]==:             if case_info[1] in (                     # '/v1/work-order/{tenantId}/{aggregateId}/repair-info',             # # # #                 # '/v1/wx/user/logout',             # # # #                     '/v1/wx/work-order/{tenantId}/{userId}/my-work-orders',             # #     '/v1/work-order/tenant/{tenantId}',                                 '/v1/stakes/section/{sectionId}/number/{stakeSerialNumber}',             # #                     '/v1/maintenance/search/select-explicit',             # #                     '/v1/collector/find-aggregate',                             ):                 params_body=case_info[cls.write_excle_case_field_desc['params_body']]                 params_path=case_info[cls.write_excle_case_field_desc['params_path']]                 if not isinstance(params_body,dict):                     params_body=json.loads(params_body)                 if not isinstance(params_path,dict):                     params_path=json.loads(params_path)                 if params_body in ({},[],[{}],None) and params_path in ({},[],[{}],None) :                     case_info[cls.write_excle_case_field_desc['params_body']]=json.dumps(params_body)                     case_info[cls.write_excle_case_field_desc['params_path']] = json.dumps(params_path)                     ex_obj.write_values(case_info)                 else:                     cls.write_cases_obj_to_excle(case_info=case_info,params_path=params_path,params_body=params_body,ex_obj=ex_obj)          # 删除params_path对应的列         ex_obj.del_ws_cols(cls.write_excle_case_field_desc['params_path']+1,is_save=False)         #重命名sheet_name         ex_obj.rename_sheet_name(src_sheet_name='Sheet',target_sheet_name='all_api_info')         ex_obj.save_workbook()   if __name__ == "__main__":     params = {"account": "demo", "pwd": "crmeb.com", "key": "533721295cb06314f4bcaacebc28e3bd", "code": "nbcw",               "wxCode": "", 'userinfo': {}, 'age': 0, 'is_vip': False, 'ext': None,               'orders': [{"order": "asc", "fileds": []}], 'orders2': [{"order2": "asc", "fileds2": []}],               "price2":0.05,"ip":""}       test_prams=OrderedDict([         ('k1',[1,2,3]),         # ('k2',[('order',[1,2,3]),('order2',[4,5,6])])     ])         params_array = [params]     params_array.extend(params_array)      #     auto_case = autoGenrateApiCaseAllpairspy()     path_dict = {'sectionId': 3448477344847734484773448477344847734484773448477344847734484773448477344847734484773448477344847734, 'stakeSerialNumber': '留言一点重要.文件发展就是资料论坛制作.留言一点重要.文件发展就是资料论坛制作.留言一点重要.文件发展就是资料论坛制作.留言一点重要.文件发展就是资料论坛制作.留言一点重要.文件发展就是资料论坛制作.'}     query_dict = {"tenantId2": 22,"df":"432fsfds"}     # url=auto_case.join_request_uri(uri="/v1/stakes/section/{sectionId}/number/{stakeSerialNumber}",path_dict=path_dict,query_dict=query_dict)     # print(url)      # json_str={'breakageThreshold': {}, 'breakageType': ['linear', 'alligator', 'pothole', 'raveling', 'explicit', 'subsidence', 'rut', 'seal', 'patch', 'horizontalCrack', 'verticalCrack'], 'endTime': 0, 'startTime': 0, 'tenantId': 0}     # print(list(auto_case.dict_parse_generator(json_str)))      # # 读取case数据     # print(auto_case.read_all_cases_data())     # auto_case.batch_write_cases_obj_to_excle()     # auto_case.join_uri_params_path('/v1/stakes/section/{sectionId}/number/{stakeSerialNumber}',{"sectionId": 0, "stakeSerialNumber": "","test":123})     # 单个写入     # auto_case.write_params_filed_detail_to_excle(params)     # auto_case.write_cases_obj_to_excle(case_info, params=params_array)     # 批量写入     # auto_case.batch_write_params_filed_detail_to_excle()     # print("case_info:before",case_info)     auto_case.batch_write_cases_obj_to_excle()     # print("case_info:after",case_info)     

发表评论

评论已关闭。

相关文章