「原创声明:保留所有权利,禁止转载」
前言
自从将项目放到 github(https://github.com/jerrylizilong/autotest_platform ), 不少人对其中的一些设计和运行原理提出了疑问。闲来无事,把其中的一些设计和架构整理一下,也是自己的一个总结。
平台化的需求
当初在尝试将原有用 python+selenium 实现的自动化框架做成平台化时,心目中最简单的需求是:
- 相关用例管理、报告查看等,都在 web 页面操作。
- 团队协同工作。
出于这个简单的目的,在 python 的几个 web 框架中,选择了轻量级的 flask,并选用 bootstrap 组件来实现前端布局 。
flask 框架简介
和大部分的 flask 项目相同,实际开发中分为以下几个模块:
1. view 目录:
view 模块是 flask 实现 web 路由跳转和接口接收的关键。
- 通过 @mod.route('/test_case') 控制路由跳转路由
- 通过 @user.authorize 控制是否需要登录用户才能访问
- 通过 return render_template("uitest/test_cases.html") 将实际的 html 页面展示给用户
- 通过 return redirect('test_cases') 进行路由跳转
- 通过 return jsonify({'code': code, 'msg': message}),{'Content-Type': 'application/json'} 实现接口的 json 数据返回
2. 功能实现:数据库操作
- 将数据库的 insert、search 、update 方法封装成公共方法
- 根据需求合理地设计对应的数据表
- 为单个模块编写对应的新增、修改、删除、查询等方法
- 为防止数据误删,建议删除时采用逻辑删除的方式,及使用状态位标记是否已删除
3. 静态文件目录:
- templates 目录:存放 html 静态页面
- static 目录:存放 js/css 以 flask 官方 demo 为基础模板,为相关页面编写了对应的 html 文件。 要点:
- 目录管理:由于涉及的页面较多,所以 templates 目录下按功能模块为子目录管理对应页面。相应地,需要在 view 中指定对应的 template 目录。
- 模板管理:将所需的菜单内容、平台标题、公用的第三方 js/css(如 boostrap )放在基础的公共模板里,方便进行统一管理。添加新菜单时,只需要在模板中添加对应元素即可。
- html 语法:熟悉 html 基本语法的使用。
简单说一下对 html\js\css 的关系理解:
html: 网页的基础布局。
- 页面上需要展示什么元素(输入框、表格、文本框、图片等),就需要对应在 html 中进行管理和排列。
- 对于我们平台的需求来说,用表格来展示查询列表,用表单进行新增、编辑管理,就可以解决 90% 的页面需求。
css : 页面元素的样式控制。
- 在简单使用的情况下,直接引用 bootstrap 的默认样式就可以了,所以基本上没有做修改。
js : 功能实现
主要控制:
- 网页和服务器后台接口的通讯。这里统一采用 ajax 实现。
- 控制页面的某些功能,如获取选择框当前所选择元素:
5. 实践:
由于我们平台的页面都是基础的增删查改,因此要做的工作是:
5.1 确立需求:
选取一个模块(如用例管理),确定需求:需要新增用例、修改用例、获取用例列表、获取用例详情、删除用例、复制用例
5.2 服务端功能实现:
- 编写对应的数据库操作方法: insert 、update、 search。
## 新增用例保存 def new_test_case(self,module,name,steps,description, isPublic): sql = string.Template('insert into test_case (module,name,steps,description,isPublicFunction) values ("$module","$name","$steps","$description",$isPublic);') sql = sql.substitute(name = name, module = module, steps = steps,description=description, isPublic=isPublic) useDB.useDB().insert(sql)
- 在 view 中编写对应的 json 接口: 新增、修改、查询(通过查询类型区分是返回列表还是返回单个用例)、复制、删除。
@mod.route('/add_test_case', methods=['POST', 'GET']) #新增用例接口
@user.authorize
def save_new_test_case():
log.log().logger.info(request)
if request.method == 'GET':
log.log().logger.info('post')
return render_template("uitest/new_test_cases.html")
if request.method == 'POST':
info = request.form
log.log().logger.info('info : %s' %info)
name = viewutil.getInfoAttribute(info,'name')
module = viewutil.getInfoAttribute(info,'module')
description = viewutil.getInfoAttribute(info,'description')
steps = viewutil.getInfoAttribute(info,'steps')
steps=steps.replace('"',"'")
type = viewutil.getInfoAttribute(info,'type')
if module == '' or name == '' or steps=='' or type=='':
return '必填字段不得为空!'
else:
if type=='公共用例':
isPublic = 1
else:
isPublic = 0
test_case_manage.test_case_manage().new_test_case(module, name, steps, description, isPublic) # 保存用例
return redirect('test_cases')
此时直接访问对应接口,可以实现增、删、改、查等功能。
5.3 页面编写和路由关联:
- 分别编写对应新增、修改、查询页面的 html 文件。
- 在 view 中编写对应路由:test_cases(用例列表页面)、add_test_case(新增用例页面)、edit_test_case(修改用例页面),与上一步的 html 文件进行关联。
@mod.route('/test_cases') @user.authorize def test_cases(): return render_template("uitest/test_cases.html")
完成这步后,此时直接访问对应的路由路径,就可以打开对应的 html 页面。
5.4 前后端关联:
- 编写 test_case.js 文件,编写对应的用例新增、修改、获取列表、获取用例详情、删除用例、复制用例等方法。
// submit form function submitAddForm() { $("#new_test_case").validate(); $.validator.setDefaults({ submitHandler: function() { document.getElementById("new_test_case").submit(); } }); }
此时需要做的,是将页面的元素与后台的接口关联起来。
到这里,相关的模块功能就实现好了。
查询:
新增:
修改:
6. 善用复制、黏贴提高开发效率
在实现后一个模块后,如果要开发新的模块,可以直接套用,只需要修改里面关键的标题、元素、id 等信息即可。 这样只需要复制、批量修改(例如直接把 test_case 替换为 test_suite),很快就能把类似的模块开发出来。
TesterHome 为用户提供「保留所有权利,禁止转载」的选项。
除非获得原作者的单独授权,任何第三方不得转载标注了「原创声明:保留所有权利,禁止转载」的内容,否则均视为侵权。
具体请参见TesterHome 知识产权保护协议。
暂无回复。