flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台,更名:FXTest 接受定制开发(java版开发完毕)
**背景: 1.平时测试接口,总是现写代码,对测试用例的管理,以及测试报告的管理持久化做的不够,
2.工作中移动端开发和后端开发总是不能并行进行,需要一个mock的依赖来让他们并行开发。
3.同时让自己锻炼去开发测试平台,掌握flask开发程序,提高自己的业务水平。
整体思路: 1.利用flask+bootstrap来进行web界面开发,对接口,接口测试用例,定时任务,测试报告的持续集成。
2.IAPTest支持接口用例管理,接口多用例测试,支持定时测试任务,测试报告持久化
3.目前mock服务支持单一path,定时任务可以开启暂停多用例执行,定时任务执行后自动发送测试报告,多用例的单次执行,单接口的调试功能。对测试环境的管理
下面来看下最后的效果图,以及附上github开源地址。
测试环境管理界面:
定时任务界面:
mock界面
测试报告界面
用例管理界面
接口管理界面
**核心代码分享区:**
定时任务对应视图开发
class AddtimingtaskView(MethodView):
@login_required
def get(self):
return render_template('addtimingtasks.html')
@login_required
def post(self):
taskname=request.form['taskname']
tinmingtime=request.form['time']
to_email_data=request.form['to_email']
cao_email=request.form['cao_email']
weihu=request.form['weihu']
if taskname =='':
flash('任务名不能为空!')
return render_template('addtimingtasks.html')
if tinmingtime =='':
flash('任务执行时间不能为空!')
return render_template('addtimingtasks.html')
if to_email_data=='':
flash('发送给谁邮件不能为空!')
return render_template('addtimingtasks.html')
if weihu=='':
flash('维护人邮件不能为空!')
return render_template('addtimingtasks.html')
taskname_is = Task.query.filter_by(taskname=taskname).first()
if taskname_is:
flash('任务已经存在请重新填写!')
return render_template('addtimingtasks.html')
new_task=Task(taskname=taskname,taskstart=tinmingtime,taskrepor_to=to_email_data,taskrepor_cao=cao_email,task_make_email=weihu,
makeuser=current_user.id)
db.session.add(new_task)
try:
db.session.commit()
flash('添加定时任务成功')
return redirect(url_for('timingtask'))
except Exception as e:
db.session.rollback()
flash('添加过程貌似异常艰难!')
return redirect(url_for('addtimingtasks'))
return render_template('addtimingtasks.html')
class Editmingtaskview(MethodView):
@login_required
def get(self,id):
task_one=Task.query.filter_by(id=id).first()
procjet=Project.query.all()
if not task_one:
flash('你编辑的不存在')
return redirect(url_for('timingtask'))
return render_template('Edittimingtasks.html',task_one=task_one,porjects=procjet)
def post(self,id):
task_one = Task.query.filter_by(id=id).first()
procjet = Project.query.all()
taskname = request.form['taskname']
tinmingtime = request.form['time']
to_email_data = request.form['to_email']
cao_email = request.form['cao_email']
weihu = request.form['weihu']
if taskname =='':
flash('任务名不能为空!')
return render_template('addtimingtasks.html')
if tinmingtime =='':
flash('任务执行时间不能为空!')
return render_template('addtimingtasks.html')
if to_email_data=='':
flash('发送给谁邮件不能为空!')
return render_template('addtimingtasks.html')
if weihu=='':
flash('维护人邮件不能为空!')
return render_template('addtimingtasks.html')
task_one.taskname=taskname
task_one.taskrepor_to=to_email_data
task_one.taskrepor_cao=cao_email
task_one.task_make_email=weihu
task_one.makeuser=current_user.id
try:
db.session.commit()
flash('编辑成功')
return redirect(url_for('timingtask'))
except:
db.session.rollback()
flash('编辑出现问题!')
return redirect(url_for('timingtask'))
return render_template('Edittimingtasks.html', task_one=task_one,porjects=procjet)
class DeteleTaskViee(MethodView):
def get(self,id):
task_one = Task.query.filter_by(id=id).first()
if not task_one:
flash('你编辑的不存在')
return redirect(url_for('timingtask'))
if task_one.status==True:
flash('已经删除')
return redirect(url_for('timingtask'))
task_one.status=True
try:
db.session.commit()
flash('删除任务成功')
return redirect(url_for('timingtask'))
except:
db.session.rollback()
flash('删除任务休息了')
return redirect(url_for('timingtask'))
@app.route('/gettest',methods=['POST'])
@login_required
def gettest():#ajax获取项目的测试用例
projec=(request.get_data('project')).decode('utf-8')
if not projec:
return []
proje=Project.query.filter_by(project_name=str(projec)).first()
if not proje:
return []
testyong=InterfaceTest.query.filter_by(projects_id=proje.id).all()
testyong_list=[]
for i in testyong:
testyong_list.append({'name':i.Interface_name,'id':i.id})
return jsonify({'data':testyong_list})
class TestforTaskView(MethodView):#为测试任务添加测试用例
def get(self,id):
procjet = Project.query.all()
task_one=Task.query.filter_by(id=id).first()
return render_template('addtestyongfortask.html',task_one=task_one,procjets=procjet)
def post(self,id):
procjet = Project.query.all()
task_one = Task.query.filter_by(id=id).first()
proc_test=request.form.get('project')
if proc_test =='':
flash(u'不能不添加测试项目!')
return render_template('addtestyongfortask.html', task_one=task_one, procjets=procjet)
test_yongli=request.form.getlist('testyongli')
if test_yongli=='':
flash(u'亲你见过只有测试项目没有测试用例的测试任务吗!')
return render_template('addtestyongfortask.html', task_one=task_one, procjets=procjet)
for oldtask in task_one.interface.all():
task_one.interface.remove(oldtask)
task_one.prject=Project.query.filter_by(project_name=proc_test).first().id
for yongli in test_yongli:
task_one.interface.append(InterfaceTest.query.filter_by(id=yongli).first())
db.session.add(task_one)
try:
db.session.commit()
flash('任务更新用例成功')
return redirect(url_for('timingtask'))
except:
flash('任务更新用例失败')
return redirect(url_for('timingtask'))
return render_template('addtestyongfortask.html', task_one=task_one, procjets=procjet)
class StartTaskView(MethodView):#开始定时任务
@login_required
def get(self,id):
task=Task.query.filter_by(id=id).first()
if len(task.interface.all())<=1:
flash('定时任务执行过程的测试用例为多用例,请你谅解')
return redirect(url_for('timingtask'))
try:
scheduler.add_job(func=addtask, id=str(id), args=str(id),trigger=eval(task.taskstart),replace_existing=True)
task.yunxing_status='启动'
db.session.commit()
flash(u'定时任务启动成功!')
return redirect(url_for('timingtask'))
except Exception as e:
flash(u'定时任务启动失败!请检查任务的各项内容各项内容是否正常')
return redirect(url_for('timingtask'))
class ZantingtaskView(MethodView):#暂停定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
try:
scheduler.pause_job(str(id))
task.yunxing_status = '暂停'
db.session.commit()
flash(u'定时任务暂停成功!')
return redirect(url_for('timingtask'))
except:
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务暂停失败!已经为您初始化')
return redirect(url_for('timingtask'))
class HuifutaskView(MethodView):#回复定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
try:
scheduler.resume_job(str(id))
task.yunxing_status='启动'
db.session.commit()
flash(u'定时任务恢复成功!')
return redirect(url_for('timingtask'))
except:
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务恢复失败!已经为您初始化')
return redirect(url_for('timingtask'))
class YichuTaskView(MethodView):#移除定时任务
@login_required
def get(self,id):
task = Task.query.filter_by(id=id).first()
try:
scheduler.delete_job(str(id))
task.yunxing_status='关闭'
db.session.commit()
flash(u'定时任务移除成功!')
return redirect(url_for('timingtask'))
except:
task.yunxing_status = '创建'
db.session.commit()
flash(u'定时任务移除失败!已经为您初始化')
return redirect(url_for('timingtask'))
定时任务所执行的func代码
def addtask(id):#定时任务执行的时候所用的函数
in_id=int(id)
task=Task.query.filter_by(id=in_id).first()
starttime = datetime.datetime.now()
star = time.time()
day = time.strftime("%Y%m%d%H%M", time.localtime(time.time()))
basedir = os.path.abspath(os.path.dirname(__file__))
file_dir = os.path.join(basedir, 'upload')
file = os.path.join(file_dir, (day + '.log'))
if os.path.exists(file) is False:
os.system('touch %s' % file)
filepath = os.path.join(file_dir, (day + '.html'))
if os.path.exists(filepath) is False:
os.system(r'touch %s' % filepath)
projecct_list = []
model_list = []
Interface_name_list = []
Interface_url_list = []
Interface_meth_list = []
Interface_pase_list = []
Interface_assert_list = []
Interface_headers_list = []
id_list = []
for task_yongli in task.interface.all():
id_list.append(task_yongli.id)
projecct_list.append(task_yongli.projects)
model_list.append(task_yongli.models)
Interface_url_list.append(task_yongli.Interface_url)
Interface_name_list.append(task_yongli.Interface_name)
Interface_meth_list.append(task_yongli.Interface_meth)
Interface_pase_list.append(task_yongli.Interface_pase)
Interface_assert_list.append(task_yongli.Interface_assert)
Interface_headers_list.append(task_yongli.Interface_headers)
apitest = ApiTestCase(Interface_url_list, Interface_meth_list, Interface_pase_list, Interface_assert_list, file,
Interface_headers_list)
result_toal, result_pass, result_fail, relusts, bask_list = apitest.testapi()
endtime = datetime.datetime.now()
end = time.time()
createHtml(titles=u'接口测试报告', filepath=filepath, starttime=starttime, endtime=endtime, passge=result_pass,
fail=result_fail, id=id_list, name=projecct_list, headers=Interface_headers_list,
coneent=Interface_url_list, url=Interface_meth_list, meth=Interface_pase_list,
yuqi=Interface_assert_list, json=bask_list, relusts=relusts)
hour = end - star
user_id = User.query.filter_by(role_id=2).first().id
new_reust = TestResult(Test_user_id=user_id, test_num=result_toal, pass_num=result_pass, fail_num=result_fail,
test_time=starttime, hour_time=hour, test_rep=(day + '.html'), test_log=(day + '.log'))
email = EmailReport.query.filter_by(role_id=2, default_set=True).first()
send_emails(sender=email.send_email, receivers=task.taskrepor_to, password=email.send_email_password,
smtp=email.stmp_email, port=email.port, fujian1=file, fujian2=filepath, subject=u'%s自动用例执行测试报告' % day,
url='%stest_rep'%(request.url_root))
db.session.add(new_reust)
db.session.commit()
mock服务的一个请求方式的代码
class MakemockserverView(MethodView):#做一个mock服务
def get(self,path):#get请求方法
huoqupath=Mockserver.query.filter_by(path=path,status=True).first()
heders=request.headers
method=request.method
if not huoqupath:
abort(404)
if method.lower() !=huoqupath.methods:
return jsonify({'code':'-1','message':'请求方式错误!','data':''})
if huoqupath.is_headers==True:
if comp_dict(heders,huoqupath.headers) ==True:
if huoqupath.ischeck==True:
paerm = request.values.to_dict()
if dict_par(paerm,huoqupath.params)==True:
if huoqupath.rebacktype == 'json':
try:
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '', 'message': 'successs', 'data': json_fan})
except:
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
else:
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
else:
return jsonify({'code': '-4', 'message': '你输入的参数不正确', 'data': ''})
else:
if huoqupath.rebacktype=='json':
try:
json_fan=json.dumps(huoqupath.fanhui)
return jsonify({'code': '', 'message': 'successs', 'data':json_fan})
except:
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype =='xml':
response=make_response(huoqupath.fanhui)
response.content_type='application/xml'
return response
else:
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
else:
return jsonify({'code': '-3', 'message': '安全校验失败!', 'data': ''})
if huoqupath.ischeck == True:
paerm = request.values.to_dict()
if dict_par(paerm, huoqupath.params) == True:
if huoqupath.rebacktype == 'json':
try:
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '', 'message': 'successs', 'data': json_fan})
except:
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
else:
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''})
else:
return jsonify({'code': '-4', 'message': '你输入的参数不正确', 'data': ''})
else:
if huoqupath.rebacktype == 'json':
try:
json_fan = json.dumps(huoqupath.fanhui)
return jsonify({'code': '', 'message': 'successs', 'data': json_fan})
except:
return jsonify({'code': '-2', 'message': '你写入的返回不能正常json!请检查', 'data': ''})
elif huoqupath.rebacktype == 'xml':
response = make_response(huoqupath.fanhui)
response.content_type = 'application/xml'
return response
else:
return jsonify({'code': '-2', 'message': '你写入的类型目前系统不支持', 'data': ''}) #
开源地址:https://github.com/liwanlei/FXTest
使用说明:
1.依赖包为requirements.txt文件下的,可能部分不全,需要什么可以自己使用中增加。
2.目前由于考虑后续迁移内部使用的话,所以移除了注册功能,改为管理员后台添加方式,默认登录:liwanlei 密码:liwanlei
3.部分功能调试还存在一定的问题,欢迎各位多提宝贵意见,
部分功能欠缺:
1.定时任务的持久化,现在处理容易受到运行过程中的宕机等情况重新启动服务器的定时任务全部需要开启
2、mock接口只能支持单一的path
3. 测试环境没有改为动态配置,动态支持。目前测试环境管理以及上线
4。部分地方可能还会有不严谨性,但是工具可以使用。
5、目前仅支持 http请求中的json格式的,
6.大家可以多提意见,后续会优化,最近一直熬夜加班可能有些消息不能及时回复,还望谅解。
作者寄语:
前进的道路我们充满着迷茫,
前进的每一步我们都会有收获。
路在脚下,我们决定不了我们的出身,但是我们可以努力改变我们未来。
告别昨天失败的自己,努力拼搏今天,成就美好明天
有问题可以联系我:QQ:952943386 email:leileili126@163.com qq群:194704520 新群:683894834
个人公众号
flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台,更名:FXTest 接受定制开发(java版开发完毕)的更多相关文章
- flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台(总结感悟篇)
前言: 在前进中去发现自己的不足,在学习中去丰富自己的能力,在放弃时想想自己最初的目的,在困难面前想想怎么踏过去.在不断成长中去磨炼自己. 正文: 时间轴 flask + Python3 实现的的AP ...
- flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台
**背景: 1.平时测试接口,总是现写代码,对测试用例的管理,以及测试报告的管理持久化做的不够, 2.工作中移动端开发和后端开发总是不能并行进行,需要一个mock的依赖来让他 ...
- HTTP API 自动化测试从手工测试到平台的演变
不管是 Web 系统,还是移动 APP,前后端逻辑的分离设计已经是常态化,相互之间通过 API 调用进行数据交互.在基于 API 约定的开发模式下,如何加速请求 / 响应的 API 测试,让研发人员及 ...
- 微信开发——微信公众平台实现消息接收以及消息的处理(Java版)
本文主要讲述了如何在微信公众平台实现消息接收以及消息的处理,使用java语言开发,现在把实现思路和代码整理出来分先给兄弟们,希望给他们带来帮助. 温馨提示: 这篇文章是依赖前几篇的文章的. 第一篇:微 ...
- 阿里云视觉智能开放平台的人脸1:N搜索的开源替代-Java版(文末赋开源地址)
一.人脸检测相关概念 人脸检测(Face Detection)是检测出图像中人脸所在位置的一项技术,是人脸智能分析应用的核心组成部分,也是最基础的部分.人脸检测方法现在多种多样,常用的技术或工具大 ...
- 《自动化平台测试开发-Python测试开发实战》新书出版了
首先 第一本书,当初在百度阅读初步写了个电子版,刚一上线不久即收到了数百位读者朋友阅读收藏购买,于是顺利成章就出版了纸质书. <软件自动化测试开发>认真看过的读者应该都知道,介绍的主要是自 ...
- Java版阿里云通信短信发送API接口实例(新)
阿里云通信(原名阿里大于)的短信服务(Short Message Service)是阿里云为用户提供的一种通信服务的能力,支持快速发送短信验证码.短信通知等. 完美支撑双11期间2亿用户,发送6亿短信 ...
- 微渠道发展 BAE交通运输平台和java呼声,微信mysql数据库开发实例 --图文开发教程
持续更新 BAE java开展mysql数据库 图文教程 BAE java语言发展mysql源码下载: 目前微信的发展.BAE开展.java开展.mysql教程开发非常,的介绍基于BAE平台.java ...
- Cucumber+Rest Assured快速搭建api自动化测试平台
转载:http://www.jianshu.com/p/6249f9a9e9c4 什么是Cucumber?什么是BDD?这里不细讲,不懂的直接查看官方:https://cucumber.io/ 什么是 ...
随机推荐
- token jwt配置
1. token jwt配置 1.1. pom <!-- token验证 --> <dependency> <groupId>io.jsonwebtoken< ...
- 解决java依赖poi导出Excel表时,没有出现下载提示的问题
转自:https://blog.csdn.net/jinchunzhao123/article/details/88626077 浏览器响应: 而且进入断点调试,所有的数据都执行了就是没有下载提示.而 ...
- linux修改当前用户环境变量永久生效
在linux环境中,修改当前用户环境变量,且永久生效的方法如下. 1,编辑~/.bash_profile文件 1 2 3 # Get the aliases and functions 4 if [ ...
- java程序员常用的cmd命令
1.查看端口号或者进程号使用情况 1.1.查看所有端口占用情况 C:\Users\Administrator>netstat -ano 活动连接 协议 本地地址 (ip:端口) 外部地址 状态 ...
- wget详解
wget命令用来从指定的URL下载文件.wget非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性,如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕.如果是服务器打断下 ...
- springmvc的控制器是不是单例模式,如果是,有什么问题,怎么解决?
默认情况下是单例模式, 在多线程进行访问的时候,有线程安全问题. 但是不建议使用同步,因为会影响性能. 解决方案,是在控制器里面不能写成员变量. 为什么设计成单例设计模式? 1.性能(不用每次请求都创 ...
- iptables 规则学习
iptables 一共有 3 张表:mangle,nat,filter mangle 表主要处理 ttl,tos,mark 等信息(进) filter 顾名思义就是过滤器,用作防火墙(出) nat 主 ...
- 10、Python迭代器与生成器(iterator、for循环、generator、yield)
一.迭代器(foreach) 1.可迭代的对象 内置有__iter__方法的都叫可迭代的对象. Python内置str.list.tuple.dict.set.file都是可迭代对象. x = 1._ ...
- STM32F103 串口-IAP程序升级
STM32F103 串口-IAP程序升级 通常情况下我们给STM32系列的单片机烧录程序文件的时候,使用SWD.J-link或者通过设置BOOT引脚后,使用串口进行程序下载,这样的方式直接一次性将程序 ...
- 基于C+OpenCV4.0的LineSegmentDetector算法实现
简单记录LSD算法的实现过程,当做备忘录用,如有问题欢迎指出和讨论 LSD的基本实现流程是计算出图像的梯度和场方向,然后对梯度进行排序,然后从大到小进行区域增长,之后对增长得到的区域求最小外接矩形,如 ...