主贴那个, 8 楼的还有问题,主贴上的是最终版, 不知道怎么删 8 楼
代码写出来了,测试了一下,应该是没有 bug 了,
在这里,你看看有没有 问题,
import json
import random
import time
from pactverify.matchers import Matcher, Like, EachLike, Enum, Term, PactVerify
from pactverify.matchers import PactJsonVerify
from pactverify.utils import generate_pact_json_by_response
from xeger import Xeger
str_xeger = Xeger(limit=10)
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,pact_type=False):
'''
校验规则:类型匹配
: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 == '$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,pact_type=pact_type)
else:
dic[key] = {}
pact_like(dic_json[key], dic[key],pact_type=pact_type)
elif isinstance(dic_json[key], (list, tuple)):
new_key = []
for key_down in dic_json[key]:
new_dic={}
pact_like(key_down, new_dic,pact_type=pact_type)
if new_dic:
new_key.append(new_dic)
else:
new_key.append(key_down)
dic[key]=new_key
else:
if pact_type:
if key not in ['$Matcher' ,'iterate_list','key_missable','nullable','example','$Enum' ] :
dic[key] = make_data(dic_json[key])
else:
dic[key] = 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, pact_type=True,)
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, pact_type=True, )
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":{ "a111a": {"$EachLike": {'k1': {'$Enum': {'$values': [11, 22],'$params': {'iterate_list': True} }} ,'232s':{'$Matcher': 12},'3s':{"$Like":22} }}}}
import time
for x in range(400):
a=time.time()
print(gerate_json_based_on_pact(pactverify_json))
print(time.time()-a)
现在麻烦的是 EachLike 那里,其他部分都很容易就写出了,今天再搞一天
先递归 LIke 然后是 EachLike 然后到 Matcher-》Term-》Enum 顺序不能乱,不然就有问题, 然后我用生成的 json 和原来的契约做契约校验,看看能不能通过, 只能这样慢慢测试再优化代码了。没想出什么好办法。 领导要我做契约测试的平台, 给消费者提供 mock 功能, 给生产者校验数据, 参考了 pact-Python 和你写的 PactVerify,目前就差一点点了。 我的 okr 全靠这个了
目前刚刚写了 json 契约的反写,5 个匹配类型,每个匹配类型都需要递归处理, 现在是多层嵌套的时候,如果是 [[[]]] 这样的还是存在问题,也有一些新 bug 还在测试中可能没暴露出来,因为还有参数问题的处理,想写出没 bug 的我感觉还得到周 5,不过已经很接近了, 原本以为 pact 包有类似的功能就不用重复造轮子了,
没想到,那么快就有回复, 根据契约来生成一个符合规则的 json ,然后 mock 或者就用来测接口报错什么的,都很方便, 然后就一直在查有没有 已有的方法, 我目前用递归写了一个 但还是有 bug 而且时间比较长,居然要 0.8 秒,昨天发完帖子就开写, 今天花了一整天了
是的, 根据契约来进 mock 数据,结构可控,数据也可控,还有一定的随机性,也能用来生成测试数据,辅助测试,
线上不好交流吧
我想知道 ,怎么根据契约生成 mock 数据呢
data=str(data)
data=data.encode('utf-8')
data = gzip.compress(data)