实现思路

1.抓取api信息(目前公司用的swagger),uri、method、params、response,解析完成后写入excle

2.读取抓取完毕的api信息,处理为allpairs所需要的ordereddict

3.调用allpairs工具生成测试用例

4.解析allpairs生成的测试用例(输出为字符串),并处理为dict

5.处理完毕后写入excel

后期优化

1.根据接口响应实现自动断言

2.增加其他接口平台的api抓取(openapi、eolink等)

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)

python实战-基于正交实验(工具:allpairs)自动生成接口异常测试用例的更多相关文章

  1. 基于MATLAB2016b图形化设计自动生成Verilog语言的积分模块及其应用

    在电力电子变流器设备中,常常需要计算发电量,由于电力电子变流器设备一般是高频变流设备,所以发电量的计算几乎时实时功率的积分,此时就会用到一个积分模块.发电量计算的公式如下:Q=∫P. FPGA由于其并 ...

  2. Django框架深入了解_05 (Django中的缓存、Django解决跨域流程(非简单请求,简单请求)、自动生成接口文档)

    一.Django中的缓存: 前戏: 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一 ...

  3. rbac介绍、自动生成接口文档、jwt介绍与快速签发认证、jwt定制返回格式

    今日内容概要 RBAC 自动生成接口文档 jwt介绍与快速使用 jwt定制返回格式 jwt源码分析 内容详细 1.RBAC(重要) # RBAC 是基于角色的访问控制(Role-Based Acces ...

  4. .net core 使用swagger自动生成接口文档

     前言 swagger是一个api文档自动生动工具,还集成了在线调试. 可以为项目自动生成接口文档, 非常的方便快捷 Swashbuckle.AspNetCore 是一个开源项目,用于生成 ASP.N ...

  5. Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据

    一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 问题二 ...

  6. swagger 自动生成接口测试用例

    ---整体更新一波--- 1.实际工作中,因为要动手输入的地方比较多,自动生成的异常接口用例感觉用处不大,就先去掉了,只保留了正常的: 2.接口有改动的,如果开发人员没有及时告知或没有详细告知,会增加 ...

  7. drf07 过滤 排序 分页 异常处理 自动生成接口文档

    4. 过滤Filtering 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持. pip install django-filter 在配置文件sett ...

  8. drf频率源码、自动生成接口文档、JWT

    目录 一.drf频率源码分析 二.自动生成接口文档 1 安装依赖 2 设置接口文档访问路径 3 文档描述说明的定义位置 4 访问接口文档网页 三.JWT 1 JWT基本原理 1.1 header 1. ...

  9. day74:drf:drf其他功能:认证/权限/限流/过滤/排序/分页/异常处理&自动生成接口文档

    目录 1.django-admin 2.认证:Authentication 3.权限:Permissions 4.限流:Throttling 5.过滤:Filtering 6.排序:OrderingF ...

  10. JApiDocs(自动生成接口文档神器)

    JApiDocs教程 前言 作为一名优秀的程序员来说,由于涉及到要与前端进行对接,所以避免不了的就是写接口文档.写完接口文档,一旦代码返回结果,参数等出现变动,接口文档还得随之改动,十分麻烦,违背了我 ...

随机推荐

  1. Codeforces Round #827 (Div. 4) A-G

    比赛链接 A 题解 知识点:模拟. 时间复杂度 \(O(1)\) 空间复杂度 \(O(1)\) 代码 #include <bits/stdc++.h> #define ll long lo ...

  2. 脚本之一键部署nexus

    NEXUS_URL="https://download.sonatype.com/nexus/3/nexus-3.39.0-01-unix.tar.gz" #NEXUS_URL=& ...

  3. Burpsuite系列1--自动扫描

    第一章 简述     Burpsuite是基于Java的用于web安全的工具,能够进行爬虫.代理.编码.密码爆破等任务,并支持对XSS漏洞.文件包含等漏洞的主动扫描或被动扫描.burpsuite2.0 ...

  4. 执行xxx.sh脚本的两种方式

    因公司测试环境的登录模式有2种,大佬们直接写了个脚本完成一键切换,看了其中的脚本文件,其中出现了send "sh out.sh\r":一直疑惑这里的sh out.sh的意思...查 ...

  5. 2022春每日一题:Day 37

    题目:[USACO14FEB]Auto-complete S 字典树套路题,字典树优化剪枝,加个cnt标记即可 代码: #include <cstdio> #include <cst ...

  6. linux下进程的实际用户ID(有效组)和有效用户ID(有效组ID)

    实际用户ID(实际组ID):标识当前用户(所属组)是谁,当用户登陆时取自口令文件. 有效用户ID(有效组ID):用来决定我们(当前进程)对文件的访问权(即实际该进程的是以那个用户运行的). 一般情况下 ...

  7. .NET MAUI 安卓应用开发初体验

    一..NET MAUI开发环境搭建&安卓SDK和安卓模拟器安装提示网络连接失败问题解决 引言 本节目标是帮助第一次搭建.NET MAUI开发环境,在下载安卓SDK和安卓模拟器过程中一直提示网络 ...

  8. 【数据库】Postgresql、PG的分区操作:创建、删除指定分区,非分区表转分区表

    〇.参考链接 一.为表创建指定分区 -- 表创建分区 参数 表名 分区序列 例如: ltc_customer , 20220915 则创建 ltc_customer_20220915 分区表 CREA ...

  9. NGINX的配置和基本使用

    Linux NGINX NGINX:engine X ,2002年开发,分为社区版和商业版(nginx plus ) 社区版:分为主线版(开发版,奇数),稳定版(偶数) Nginx官网:http:// ...

  10. 手写promise解决回调地狱问题

    在介绍promise之前我们先来看一段代码: 根据案例我们可以看出,这段代码可以无限的嵌套下去,但是每嵌套一层,代码的运行就会降低,而解决回调地狱最好的办法就是new promise 一.什么是 pr ...