举个例子,我现在有一个 json 契约。一个 python 契约,然后我现在想实现
1,根据 json 契约,自动生成一个符合契约规则的随机 json
2,根据 python 契约,自动生成一个符合契约规则的随机 json
我看过 pact 包,但是感觉也根据契约反写的方法
原来的包也没有,
如果自己实现,感觉有点困难,
原来的帖子地址。http://testerhome.com/topics/22561
我用一直用的这个做契约测试,感觉比 pact 好用多了,做了封装到平台,也做了 mock 那部分,然后就想到这个,
最终方案,还需要运行一段时间 debug 一下
import random
from pactverify.matchers import PactJsonVerify
from xeger import Xeger
str_xeger = Xeger(limit=30)
def generateChr():
#gbk2312对字符的编码采用两个字节相组合, 第一个字节的范围是0xB0 - 0xF7, 第二个字节的范围是0xA1 - 0xFE.在head区号为55的那一块最后5个汉字是乱码,为了方便缩减下范围
temp='{0:x} {1:x}'.format(random.randint(0xb0, 0xf7), random.randint(0xa1, 0xf9) )
chr=bytes.fromhex(temp).decode('gb2312')
return chr
def make_data(data_type):
if isinstance(data_type, int):
old_body = int(str_xeger.xeger(r'[0-9]{%d}' % random.randint(1, 10)))
elif isinstance(data_type, str):
old_body = str_xeger.xeger(r'[a-zA-Z0-9%s]{%d}' %(generateChr(),random.randint(1, 10)) )
elif isinstance(data_type, float):
old_body = float(str_xeger.xeger(
r'[0-9]{%d}' % random.randint(1, 5)) + '.' + str_xeger.xeger(
r'[0-9]{%d}' % random.randint(1, 10)))
else:
old_body =data_type
return old_body
def pact_like(dic_json,dic):
'''
校验规则:类型匹配
:param dic_json:
:param dic:
:return:
'''
if isinstance(dic_json, dict):
for key in dic_json:
if isinstance(dic_json[key], dict):
for key_down in dic_json[key]:
if key_down == '$Like':
if isinstance(dic_json[key][key_down], dict) and '$values' in dic_json[key][key_down].keys() :
dic_json[key] = make_data(dic_json[key][key_down]['$values'])
else:
dic_json[key] = make_data(dic_json[key][key_down])
pact_like(dic_json, dic)
else:
dic[key] = {}
pact_like(dic_json[key], dic[key])
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
pact_like(key_down, new_dic)
if new_dic:
new_key.append(new_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
if key not in ['$Matcher', '$values', '$params', '$EachLike', '$Enum', '$Term',
'iterate_list', 'key_missable', 'nullable', 'dict_emptiable', 'jsonloads' 'example', 'Term',
'minimum', 'extra_types']:
dic[key] = make_data(dic_json[key])
else:
dic[key] = dic_json[key]
return dic
def pact_EachLike(dic_json,dic):
'''
校验规则:数组类型匹配
EachLike 下的项目 如果没有特定,都按LIke实现
:param dic_json:
:param dic:
:return:
'''
if isinstance(dic_json, dict):
for key in dic_json:
if isinstance(dic_json[key], dict):
if key =='$EachLike':
dic=[dic_json[key]]
return dic
else:
for key_down in dic_json[key]:
if key_down == '$EachLike':
ruest_EachLike = []
minimum = 1
if isinstance( dic_json[key][key_down], dict) and '$values' in dic_json[key][key_down].keys():
#判断是否带参数
if '$params' in dic_json[key][key_down].keys():
if 'minimum' in dic_json[key][key_down]['$params'].keys():
minimum=dic_json[key][key_down]['$params']['minimum']
old_body = dic_json[key][key_down]['$values']
for x in range(random.randint(minimum,10)):
if isinstance(dic_json[key][key_down]['$values'],dict):
EachLike_dic = {}
pact_like(old_body, EachLike_dic)
else:
EachLike_dic=make_data(dic_json[key][key_down]['$values'])
ruest_EachLike.append(EachLike_dic)
dic_json[key]=ruest_EachLike
else:
ruest_EachLike=[]
for x in range(random.randint(minimum,10)):
if isinstance(dic_json[key][key_down], dict):
EachLike_dic = {}
old_body = dic_json[key][key_down]
pact_like(old_body, EachLike_dic )
old_body=EachLike_dic
else:
old_body= make_data(dic_json[key][key_down])
ruest_EachLike.append(old_body)
dic_json[key]=ruest_EachLike
pact_EachLike(dic_json, dic,)
else:
dic[key] = {}
pact_EachLike(dic_json[key], dic[key],)
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
retun_dic=pact_EachLike(key_down, new_dic,)
if new_dic:
new_key.append(new_dic)
elif retun_dic:
new_key.append(retun_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
dic[key] = dic_json[key]
def pact_Matcher(dic_json,dic):
'''
校验规则:值匹配 不存在随机
:param dic_json:
:param dic:
:return:
'''
if isinstance(dic_json, dict):
for key in dic_json:
if isinstance(dic_json[key], dict): # 如果dic_json[key]依旧是字典类型
for key_down in dic_json[key]:
if key_down == '$Matcher':
if isinstance(dic_json[key][key_down], dict) and '$values' in dic_json[key][key_down].keys() :
dic_json[key] = dic_json[key][key_down]['$values']
else:
dic_json[key] = dic_json[key][key_down]
pact_Matcher(dic_json, dic)
else:
dic[key] = {}
pact_Matcher(dic_json[key], dic[key])
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
pact_Matcher(key_down, new_dic)
if new_dic:
new_key.append(new_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
dic[key] = dic_json[key]
def pact_Enum(dic_json,dic):
'''
校验规则:枚举匹配
:param dic_json:
:param dic:
:return:
'''
if isinstance(dic_json, dict):
for key in dic_json:
if isinstance(dic_json[key], dict): # 如果dic_json[key]依旧是字典类型
for key_down in dic_json[key]:
if key_down == '$Enum':
if isinstance(dic_json[key][key_down], dict) and '$params' in dic_json[key][key_down].keys():
if 'iterate_list' in dic_json[key][key_down]['$params'] and dic_json[key][key_down]['$params']['iterate_list'] :
dic_json[key] = dic_json[key][key_down]['$values']
else:
print(dic_json ,3333)
dic_json[key] = random.choice(dic_json[key][key_down]['$values'])
else:
dic_json[key] = random.choice(dic_json[key][key_down])
pact_Enum(dic_json, dic)
else:
dic[key] = {}
pact_Enum(dic_json[key], dic[key])
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
pact_Enum(key_down, new_dic)
if new_dic:
new_key.append(new_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
dic[key] = dic_json[key]
def pact_Term(dic_json,dic):
if isinstance(dic_json, dict):
for key in dic_json:
if isinstance(dic_json[key], dict):
for key_down in dic_json[key]:
if key_down == '$Term':
if isinstance(dic_json[key][key_down], dict) and '$values' in dic_json[key][key_down].keys():
if isinstance(dic_json[key][key_down]['$params']['example'] ,int):
dic_json[key] = int(str_xeger.xeger(dic_json[key][key_down]['$values']))
elif isinstance(dic_json[key][key_down]['$params']['example'] ,float):
dic_json[key] = float(str_xeger.xeger(dic_json[key][key_down]['$values']))
else:
dic_json[key] = str_xeger.xeger(dic_json[key][key_down]['$values'])
else:
assert False,'契约中的Term类数据不正确'
pact_Term(dic_json, dic)
else:
dic[key] = {}
pact_Term(dic_json[key], dic[key])
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
pact_Term(key_down, new_dic)
if new_dic:
new_key.append(new_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
dic[key] = dic_json[key]
def gerate_json_based_on_pact(pactverify_json):
'''
传入契约,根据契约生成对应的json
支持
基本的匹配类型,包括含有参数的情况
1、Matcher 类,校验规则:值匹配
2、Like 类,校验规则:类型匹配
3、EachLike 类,校验规则:数组类型匹配
4、Term 类,校验规则:正则匹配
5、Enum 类,校验规则:枚举匹配
每一级的处理都是独立的递归处理,如果json深度太深,性能会存在问题
:param pactverify_json:
:return:
'''
try:
mPactVerify = PactJsonVerify(pactverify_json, hard_mode=True, separator='$')
test_json = {'test': pactverify_json}
pact_json = {} # 生成的json
# 处理like类型
pact_json = pact_like(test_json, pact_json)
# 基于上面的结果处理EachLike类型
test_json = pact_json
pact_json = {}
pact_EachLike(test_json, pact_json)
# Term 类处理 正则
test_json = pact_json
pact_json = {}
pact_Term(test_json, pact_json)
# Enum类型处理
test_json = pact_json
pact_json = {}
pact_Enum(test_json, pact_json)
# pact_Matcher类型处理
test_json = pact_json
pact_json = {}
pact_Matcher(test_json, pact_json, )
pact_json = pact_json['test']
mPactVerify.verify(pact_json)
if mPactVerify.verify_result == True:
return pact_json
else:
return {'error': 'mockjson 生成失败 ', 'verify_info': mPactVerify.verify_info}
except Exception as e:
return {'error': 'mockjson 生成失败 ', 'verify_info': str(e)}
pactverify_json={
"$Like":{
"a":{"$EachLike":11},
"b":{"$Matcher":22},
"c":{"$Like":22},
"d":{'$Term': {'$values': r'^\d{1}$','$params': {'example': 1}}},
'e':{'$Enum': [11, 22]},
'f':23,
'g':'rrr',
"aa":{"$EachLike":{'k1': 'v1'}},
"aaa":{"$EachLike":['k1', 'v1']},
'code': 0,
'msg': {'$Like': {"id": 1,"name": 'lili'}},
'ms122g': {'$Like': {"id": 1, "name": 'lili','999': {"$EachLike":11} }},
'9232': {'$Like': {"id": 1, "name": 'lili', '999': {"$EachLike": {'k1': {'$Like': {'$values': {'k1': 'v1'},'$params': {'nullable': True}} } }}}},
'19232': {'$Like': {"id": 1, "name": 'lili', '999': {"$EachLike": ['k11', 'v1']}}},
'192232': {'$Like': {"id": 1, "name": 'lili', '999': {"$EachLike": {'$EachLike': {"id": 1,"name": 'lili'}} }}},
'old_data': {'$Like': {
'msg': 'success',
'code': { '$Matcher': {'k':'3'}},
'aa':{ '$Enum': [11, 22]},
'shuzi':{
'$Term': {
'$values': r'^\d{1}$',
'$params': {'example': 1}
}},
'data': {
'$Like': {
'type_id': {'$EachLike':2222},
'name': {'$Like': '9999999'},
'order_index': {'$Enum': [111, 1223, 166, 121]},
'status': 1,
'subtitle': {
'$Like':{
'te22st':555,
'331113': {'$Enum': [11, 223, 66, 21]},
'9983':{'$EachLike':{'k1': '11111'}}
}
},
'game_name': {'$EachLike':{'test': {'$Enum': [191, 5223, 626, 21111]} ,
'test2':{'$Like': '9999999'},
}},
'user_name':{'$EachLike': {
'$values': {'k2231': 'v1'},
'$params': {'minimum': 0}
}},
'kkkk': {'$Enum': {
'$values': [99, 88],
'$params': {'iterate_list': True}
}
}
}
}
}},
'gg': {'$Enum': {'$values': [11, 22],'$params': {'iterate_list': True}}},
'dde':{'$EachLike': {'$values': {'k1': 'v1'},'$params': {'minimum': 0}}},
"a111a": {"$EachLike": {'k1': {'$Enum': {'$values': [11, 22],'$params': {'iterate_list': True} }} ,'232s':{'$Matcher': 12},'3s':{"$Like":22} }},
"768833": {"$EachLike": {'k1': {'$Enum': {'$values': [11, 22],'$params': {'iterate_list': True} }} ,'2228s':{'$Matcher': 12},'3333s':{"$Like":22} }},
'8322' : {'$Like': {'$values': {'k1': 'v1'},'$params': {'nullable': True}}},
'age': {
'$Term': {
'$values': r'^\d{1}$',
'$params': {'example': 1, 'key_missable': True}
}
},
'm1sg': {
'$Matcher': {
'$values': 'success',
'$params': {'key_missable': True}
}
},
'cod9999e': {
'$Like': {
'$values': 0,
'$params': {'key_missable': True}
}
},
}
}
aaa={"$Like": {"pact_json": { "$Like":333333 } }}
for x in range(1):
print(gerate_json_based_on_pact(aaa))
print(gerate_json_based_on_pact(pactverify_json))