▼
关注测试君 | 会上瘾
在上一篇《unittest批量组织依赖用例(一)》,我们讲了在拿到依赖case的情况下如何批量生成测试方法,那么如何组织依赖case呢,我们今天来试试~本次以Excel为例,做一个简单的依赖case读取与执行~实现代码与业务逻辑解耦(这篇只介绍如何设计,具体设计可以自行根据需求变化~)
第一步,搭建几个依赖接口,流程如下:
那么我们这次脚本的流程图设计如下~
上次用flask,那我们这次还是用django写几个简单依赖接口吧~ views中伪代码如下(路由省略):
def test_api_01(request):
global A
if request.method =='POST':
username = request.POST['username']
password = request.POST['password']
if username=='root' and password=='123456':
A=random.randint(111111,999999)
resp = {
'number': A,
}
return HttpResponse(json.dumps(resp), status=520, content_type="application/json")
else:
resp = {
'status':'error',
}
return HttpResponse(json.dumps(resp), status=520, content_type="application/json")
else:
return render(request,"api1.html")
def test_api_02(request):
global A
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
number = request.POST['number']
number2 = request.POST['number2']
if username == 'root' and password == '123456' and int(number)==int(A) and number2=="ASDYUASIDKLASD":
resp = {
'code': '200',
'message': 'success',
}
return HttpResponse(json.dumps(resp),status=520, content_type="application/json")
else:
resp = {
'code': '100',
'message': 'fail',
}
return HttpResponse(json.dumps(resp), status=444, content_type="application/json")
else:
return render(request, "api2.html")
def test_api_03(request):
global A
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
if username == 'root' and password == '123456':
resp = {
'code': '200',
'orderid': '78562564DASDJSK655656',
}
return HttpResponse(json.dumps(resp),status=520, content_type="application/json")
else:
resp = {
'code': '100',
'message': 'fail',
}
return HttpResponse(json.dumps(resp), status=444, content_type="application/json")
else:
return render(request, "api2.html")
def test_api_04(request):
global A
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
if username == 'root' and password == '123456':
resp = {
'code': '200',
'number2': 'ASDYUASIDKLASD',
}
return HttpResponse(json.dumps(resp),status=520, content_type="application/json")
接下来我们新建一个excel,我们这次只看关于body中的依赖,其他字段设计暂时忽略。api_sum_list 为汇总表记录所有api,而api对应的具体测试用例分别在各自的sheet,url列可以自行填写不同环境的baseURL,当然也可以在配置文件中进行配置~
咱们再来看看具体API中依赖表的设计(可点击查看大图),依赖数据存于dependenceCase 这一列,多个依赖为了方便看起来不费劲,我用‘===’当做分割符~ 而data中的占位符用%s表示~ 如果请求中有%怎么办呢~可以用%%来代替~这一列中的sheet:代表依赖case所在的sheet ,case 代表所在sheet中的位置,dependence 代表需要保存依赖case中的返回值~
哈哈那么如何组织case的运行顺序呢,从流程图上不难看出 A依赖B,B依赖C,C依赖D 那么则他们的运行顺序则为 D=>C=>B=>A,也就是入栈的方式,先进后出~那么如何获得到最后一层依赖数据呢~那就要去递归啦~伪代码如下:
if api_data['dependenceCase']:
if '===' in api_data['dependenceCase']: #多平行依赖
for i in (api_data['dependenceCase']).split('==='):
dependenceCase = exchange(i)
if run == 'y':
depencedata(dependenceCase)
else:
dependenceCase = exchange(api_data['dependenceCase'])
depencedata(dependenceCase)
其中exchange 方法用来生成依赖字典,传入depencedata,更方便的是从chrome抓如的请求经常为 XX:XX 使用此方法可以转化成字典,自动使用formdata进行请求~
def exchange(data):
data_star = data.replace(':',' ').split()
data = {data_star[x]: data_star[x + 1] for x in range(len(data_star) - 1) if x % 2 == 0}
return data
重点来了,递归函数如下~也就是传入依赖sheet ,case,dependence,将会递归到最后一层,然后依次请求。
def depencedata(dependenceCase):# 依赖case 的递归提取传入的case
if dependenceCase:
depen_st = TestCases().api_detail(data_sum_list=None,
assign=dependenceCase["sheet"],
case=dependenceCase["case"]) # 取到Case 后继续取的依赖用例
depen = depen_st[0]
url_new = depen['url']
header_new = exchange(depen['header'])
data_mode =depen['data_mode']
if 'json' in data_mode:
if not isinstance(depen['data'], str):
data_new = str(depen['data'])
else:
data_new = str(depen['data'])
else:
data_new = exchange(depen['data']) # 转化成字典 默认formdata
dependence_new = depen['dependence']
method = depen['method']
dependencecase = exchange(depen['dependenceCase'])
if dependencecase:
depencedata(dependencecase)
if dependence_new:
data_end = eval(str(data_new) % (getattr(dependenceClass,dependence_new)))
if method == 'post':
req = requests.post(url=url_new, data=data_end, headers=header_new, verify=False)
depen_name = dependenceCase['dependence']
if isinstance(req.text,str):
json_data = eval(req.text) #依赖dict
depen_data = json_ex(param=depen_name, json_c=json_data) #提取依赖
setattr(dependenceClass,str(depen_name),depen_data)
if method == 'get':
req = requests.get(url=url_new, data=data_end, headers=header_new, verify=False)
depen_name = dependenceCase['dependence']
if isinstance(req.text,str):
json_data = eval(req.text)
depen_data = json_ex(param=depen_name, json_c=json_data) #提取依赖
setattr(dependenceClass, str(depen_name), depen_data)
其中 json_ex 这个方法,可以快去提取需要的key对应的value,如果json数据量大不需要再[][][]一层一层的去写啦~(使用yield 记住所在递归位置)
def json_recursion(dic,rec=[]):
if isinstance(dic, dict):
for k,v in dic.items():
if isinstance(v,dict):
for d in json_recursion(v, rec + [k]):
yield d
elif isinstance(v,list):
for i in v:
for d in json_recursion(i, rec + [k]):
yield d
else:
yield rec+[k,v] #output
else:
yield dic
def json_ex(param,json_c,back=True):
"""
:param param: 提取key值
:param json_c: 提取json
:param back: 是否return 第一次匹配值
:return:
"""
applist=[]
for i in json_recursion(dic=json_c):
# print(i)
if param in str(i):
applist.append(['.'.join(i[0:-1]),i[-1]])
if len(applist)==1:
return applist[0][1]
elif len(applist)>1 and back :
return applist[0][1]
else:
return applist
这样大概的框架已经形成啦,再把咋们上次写的装饰器用上稍作补充~得到run_all文件,为啥这么写?哈哈哈 其实这么写很麻烦~但是我觉得看着很好看哈哈~
@runTime
@deco_setarrt
@run(title="Api Test",description="API TEST RESULTS", tester="Ayo")
def run():
Log.info('======>测试已完成')
run一下瞧瞧~哈哈我们依赖的case 全在我们主case 运行之前全部跑完~
我们再多run 几个case~并结合前端页面进行结果审查~(本次暂不详细介绍如何结合vue+element UI)
最后看看咋们运行邮件报告~ 嘻嘻这样一个完整的 用例脚本就这么设计好啦~可以根据自己项目进行diy,主要思想就是递归取依赖~