▼
关注测试君 | 会上瘾
对于接口自动化,设计上的难点有:如何保证测试脚本的可复用性,以及脚本正确性。个人认为脚本的正确性是基于脚本的可复用性而言的,因为只有可复用性高使用频率大,才会慢慢的发现并改进脚本中的问题。经常看到很多小伙伴写着线性的一次性脚本,一次写完,第二次换个接口又要重新组织代码,忽略组织代码花去的时间,那谁又能保证你新组织的代码的正确性呢? 总而言之,我们写脚本的目的是以测试脚本测试系统,而不是以系统来测试我们写的测试脚本呀~如果使用你的脚本出了问题,你第一时间想的是修复你的脚本,那么就本末倒置啦~
那么如何设计出一个可复用性高的测试脚本呢?嘻嘻嘻,那就要从接口依赖说起来,只有搞定了依赖接口,才可以为设计一个高可用的测试脚本打下基础~那就开始吧~
首先先设计一个测试依赖接口,流程如下~
我们使用flask 编写对应的简单测试接口:
from flask import Flask, request,jsonify
from flask_cors import *
import json
class Config(object):
DEBUG = True
JSON_AS_ASCII = False
app = Flask(__name__)
CORS(app, supports_credentials=True)
app.config.from_object(Config)
A=1
B=2
C=3
D=4
@app.route('/DepenceOne', methods=['GET'])
def DepenceOne():
if request.method == "GET":
return jsonify({'One': A})
@app.route('/DepenceTwo', methods=['POST'])
def DepenceTwo():
if request.method == 'POST':
data = request.get_data()
json_data = json.loads(data.decode("utf-8"))
return jsonify({'Two': B+int(eval(json_data)['One'])})
@app.route('/DepenceThr', methods=['GET'])
def DepenceThr():
if request.method == "GET":
return jsonify({'Thr': C})
@app.route('/DepenceFou', methods=['POST'])
def DepenceFou():
if request.method == 'POST':
data = request.get_data()
json_data = json.loads(data.decode("utf-8"))
return jsonify({'Fou': D+int(eval(json_data)['Thr'])})
@app.route('/DepenceFive', methods=['POST'])
def DepenceFive():
if request.method == 'POST':
data = request.get_data()
json_data = json.loads(data.decode("utf-8"))
if int(eval(json_data)['Two'])+int(eval(json_data)['Fou'])==10:
return jsonify({'data':'success'})
if __name__ == '__main__':
app.config['JSON_AS_ASCII'] = False
app.run('0.0.0.0',port=9999,debug=True)
接下来我们来设计测试类,按照常理我们是不是要写五个测试方法按照接口流程来组织执行顺序?不不不,我们今天就换个方法吧~ 我们先写一个requests 方法,我们采用昨天讲过的添加类属性保存依赖值~ 点击查看原文哟~
def requestRun(url, data, method,save,depence):
if depence:
data = json.dumps(str(data)% tuple(getattr(Depence,str(i)) for i in depence))
if method =='post':
req = requests.post(url=url,data=data)
else:
req = requests.get(url=url, data=data)
if save:
setattr(Depence, save, eval(req.text)[save])
现在新建一个测试类,并将requests方法放入:
class Testcases(unittest.TestCase):
def requestRun(self,url, data, method, save, depence):
if depence:
data = json.dumps(str(data) % tuple(getattr(Depence, str(i)) for i in depence))
if method == 'post':
req = requests.post(url=url, data=data)
else:
req = requests.get(url=url, data=data)
if save:
setattr(Depence, save, eval(req.text)[save])
是不是有人要问了,unittest用例不是要以test开头吗?哈哈哈,接着看,我们现在要用到python的语法糖啦~写一个装饰器,返回requestRun函数~你们是不是已经猜到了?嘻嘻~
@staticmethod
def getTestFunc(args):
def func(self):
self.requestRun(**args)
return func
现在假设我们已经拿到了api的执行顺序,一个list(下次再将如何组织api的执行顺序,以及数据源模板设计)例如:
list_data=[{'url':'http://192.168.11.9:9999/DepenceOne','data':None,'method':'get','save':'One','depence':None},
{'url':'http://192.168.11.9:9999/DepenceTwo','data':{'One':'%s'},'method':'post','save':'Two','depence':['One']},
{'url':'http://192.168.11.9:9999/DepenceThr','data':None,'method':'get','save':'Thr','depence':None},
{'url':'http://192.168.11.9:9999/DepenceFou','data':{'Thr':'%s'},'method':'post','save':'Fou','depence':['Thr']},
{'url':'http://192.168.11.9:9999/DepenceFive','data':{'Two':'%s','Fou':'%s'},'method':'post','save':None,'depence':['Two','Fou']},
]
接下来,我们要把我们测试数据组成一个个独立的方法,setattr 让Testcases 拥有更多的方法属性。
def ProTestCases():
for args in range(len(list_data)):
setattr(Testcases, 'test_func_%s' % (args),Testcases.getTestFunc(list_data[args]))
总的代码如下,也就是执行测试类之前必须先把继承unittest的测试类添加属性~
import requests
import unittest
import json
from uniTest.depence import *
list_data=[{'url':'http://192.168.11.9:9999/DepenceOne','data':None,'method':'get','save':'One','depence':None},
{'url':'http://192.168.11.9:9999/DepenceTwo','data':{'One':'%s'},'method':'post','save':'Two','depence':['One']},
{'url':'http://192.168.11.9:9999/DepenceThr','data':None,'method':'get','save':'Thr','depence':None},
{'url':'http://192.168.11.9:9999/DepenceFou','data':{'Thr':'%s'},'method':'post','save':'Fou','depence':['Thr']},
{'url':'http://192.168.11.9:9999/DepenceFive','data':{'Two':'%s','Fou':'%s'},'method':'post','save':None,'depence':['Two','Fou']},
]
class Testcases(unittest.TestCase):
def requestRun(self,url, data, method, save, depence):
if depence:
data = json.dumps(str(data) % tuple(getattr(Depence, str(i)) for i in depence))
if method == 'post':
req = requests.post(url=url, data=data)
else:
req = requests.get(url=url, data=data)
if save:
setattr(Depence, save, eval(req.text)[save])
@staticmethod
def getTestFunc(args):
def func(self):
self.requestRun(**args)
return func
def ProTestCases():
for args in range(len(list_data)):
setattr(Testcases, 'test_func_%s' % (args),Testcases.getTestFunc(list_data[args]))
最后我们另起一个py,导入测试类,运行~ yeah 完美,全部通过~
ProTestCases()
suite = unittest.TestLoader().loadTestsFromTestCase(Testcases)
with open(report_file + r'\TestReport.html', 'wb') as f: # 从配置文件中读取
HTMLTestRunner(stream=f, title='Api Test', description='依赖Demo', tester='ayo').run(suite)
每日一练,这段代码会输出什么呢~可以评论哈哈哈
def foo():
return [lambda x: i+x for i in range(4)]
print([x(3) for x in foo()])