51Testing软件测试论坛

标题: Web前端性能测试平台开发(Flask) [打印本页]

作者: lsekfe    时间: 2020-4-15 13:27
标题: Web前端性能测试平台开发(Flask)

听说你也在用Python?那一起愉快地玩耍吧—by晴空
开篇先打个小广告,在《牛刀小试-LR性能测试》那篇小文中我有说到性能测试要做到性能的原子化这样我们把性能可以分为前端,网络,中间件,App(应用),操作系统,数据库等,今天我们来一起开发一个专门对Web前端性能自动化平台(后续可以在该版本的技术和基础上完善其他功能比如说:接口的自动化和接口性能以及对其他层的监控数据做可视化)。
一:要啥自行车?奢侈!
大家都懂敲代码之前有很多事情要做并且是最重要的事情(能敲代码的人多的是,最重要的是能产出发现问题并给出解决策略的idea),what’s this? 当然是需求分析。
我们的愿景:
实现Web前端性能测试(自动遍历所有页面) 监控每个页面加载时间段的耗时,并且统计每个页面中附加的资源(css/js/img/XmlHttpRequest)最后利用精美的图表作展现。
技术可行性分析:
自动遍历所有页面?没问题啊 webdriver是这块儿的利器啊。
如何统计页面加载时间呢?performance.timing绝对靠谱。
哪儿有精美的图表?百度Echarts团队为你分忧解难。
技术选型:
这是个非常值得探讨的问题,有些Leader是综合团队现状和实施成本(新技术是需要花时间学啊);有些知乎党就不说了啥最新用啥只用最新的不用最合适的;当然还有一些人完全是靠自己的兴趣拍脑袋决定的。
我们这里选择python+webdriver+flask+sqlite+bootstrap+jquery来完成我们这个小平台的开发,至于为嘛会选择这几种技术,学习成本低开发效率高总而言之一句话 ROI高!
好嘞~ 童鞋们可以先脑补下自己想要什么样的交互页面,我这里给出一个最简单的嘿嘿~
主页面(展示统计到的页面信息并以堆叠图展示性能数据):
[attach]128674[/attach]
页面详情页面(展示页面中附加资源的组成以及该页面历史版本的数据对比图)
[attach]128675[/attach]
[attach]128676[/attach]
[attach]128677[/attach]

(ps:对技术选型这块儿同学们可以根据自己的需要做改变
如果你不想用flask 可以换成Django框架
如果你不想用sqlite数据库可以换成mysql或者其他的NoSql类数据库
如果你不想用jquery 那你的选择就更多了什么React,Nodejs,Vuejs,Angularjs还有啥backbone.js眼花缭乱。
我个人喜好小而精致的东西就拿flask来说吧它是个微型框架远远没有Django重,但是flask丰富的插件可以供我们快速地完成任务。所以嘛要啥Django 要啥自行车别太奢侈
技术没有Low不Low之分!只有适合不适合。





作者: lsekfe    时间: 2020-4-15 13:31
二:这个轮椅是专门为你设计的
这里是对应软件工程里的概要设计阶段。经过前面的梳理我们很清楚地知道自己想要的是什么了。嗯~  接下来咱把硬邦邦的需要转化为软件工程里的东东吧。
数据库:我们建两张表分别存放所有页面的统计数据就叫WebPages,还需要建立一张表来存放每个页面的详细信息我们叫PageDetail。
建表语句如下:
CREATE TABLE [PageDetail] (
  [project] text,
  [resourceName] text,
  [requestType] text,
  [pageRequestCount] INTERGER,
  [resourcetSize] INTERGER,
  [resourceLoadTime] INTERGER,
  [createTime] datetime,
  [pageName] text,
  [pageLoadTime] INTEGER);

CREATE TABLE WebPages (project text, name text ,url text  ,direct INTERGER ,domReady INTERGER, loadEvent INTERGER ,request INTERGER ,ttfb INTERGER,loadPageAll  INTERGER ,ifredirect INTERGER, createTime  datetime);

接口:
我们重新执行脚本来统计前端性能的话需要调用接口。
我们就命名一个接口吧 python-flask里接口的定义很简单哦~
  1. # 重新执行测试脚本
  2. @app.route('/redo', methods=['GET', 'POST'])
  3. def redo():
  4. if request.method == 'GET':
  5. return u'该接口不支持GET方法访问'
  6. else:
  7. # 向测试环境发生get请求来验证测试环境是否存在
  8. if env_test_code == 200:
  9.         # 重新执行测试脚本
  10. Else:
  11. Return 测试环境不存在
复制代码

如果我们选择不同版本的话我们也需要调用接口来返回所选版本的测试数据:
  1. @app.route('/index', methods=['GET', 'POST'])
  2. def index():
  3. if request.method == 'POST':
  4. # 从ajax请求中取参数selected_version 取不到则为null
  5. version_text = request.form.get("selected_version", "null")
  6. else:
  7.         version_text = '默认版本号'
  8.     # 接下来巴拉巴拉从sqlite中取数据并返回
复制代码




作者: lsekfe    时间: 2020-4-15 13:37
三:走两步~  走两步!
让我们开始敲代码吧?好啊!来吧!
接下来我们先完成前端部分的开发工作然后再搞后台部分的任务,bootstrap&flask学起!

3.1:flask环境搭建和基础知识
啥是flask?
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。
Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。然而,Flask保留了扩增的弹性,可以用Flask-extension加入这些功能:ORM、窗体验证工具、文件上传、各种开放式身份验证技术。

环境搭建:
先用pip安装virtualenv库~ (这样做是为了单独拉一个python环境出来以便我们一台服务器上可以跑多套服务)
Dos窗口里敲命令:pip install virtualenv
然后,新建一个目录我们就叫AutoMan吧,Dos窗口里切换到AutoMan目录后执行:virtualenv venv(创建虚拟环境目录)
我们如果要在virtualenv里安装需要的包,需要先激活虚拟环境(切到venv/scirpts里执行activate)然后再执行pip安装即可。
我们这里需要安装的环境有flask,selenium,requests。我们可以分别执行安装,也可以将flask,selenium,requests放到requirement.txt文件里然后执行pip install –r requirement.txt。
[attach]128678[/attach]
目录说明:
1:Web我们的项目目录
1.1:static存放静态文件的目录,它下面又分为css,img,js目录分别存放样式文件图片和js文件(下载jquery.js放到js目录下,bootstrap.css放到css目录下)。
1.2:templates目录存放的是我们的html静态页面。
1.3:views.py里定义了接口以供前端发起请求。
1.4:__init__.py里初始化了Web这个服务。
2:和Web平级的venv是我们flask虚拟环境的目录,发布的时候不需要它。
3:AutoMan.db我们用到的sqlite数据库文件。
4:config.py文件里是我们用到的配置信息,比如说页面信息,统计性能的js方法等。
5:manage.py是我们程序的执行入口。
我们先来初始化我们的应用:
在__init__.py文件里输入:
[attach]128679[/attach]
接着,我们可以尝试下在页面输出一个字符串是什么感受,嗯啊,感受!
在views.py文件里输入:

[attach]128680[/attach]
  1. # 定义路由
  2. @web_app.route('/')
  3. def root():
  4. return 'Hello Flask'

  5. 在manage.py文件里启动我们的应用:
  6. from Web import web_app
  7. web_app.run(host='0.0.0.0', port=5566)
复制代码

启动服务(我用的是pycharm调试),在浏览器里输入http://localhost:5566
[attach]128681[/attach]
是不是很神奇~~~~   我们继续补充下flask中的路由知识。
Flask中route() 装饰器把一个函数绑定到对应的 URL 上,灰常简单!
比如下面的
  1. @app.route('/ajaxAnalyse')
  2. def ajax_analyse():
  3. return render_template('ajaxAnalyse.html')
  4. 我们通过浏览器访问localhost:5566/ajaxAnalyse,flask路由会指定该地址并返回ajaxAnalyse.html模板交给浏览器渲染后呈现给我们。

  5. @app.route('/resource_<name>_<version>')
  6. def resource_analyse(name, version):
  7. print name
  8. return render_template('pages_detail.html')
复制代码
如果我们想在路由中使用变量,<>包含起来即可,上面这个例子中我们使用两个变量,分别是name(页面名称)和version(项目版本)。
好嘞~  接下来就简单了,我们开始构造url路由。
首先是首页,首页的话我们想展示所有页面的统计信息和堆叠图。所以下面的代码即可实现(我们从数据库中读取数据并和html模板一起返回让浏览器渲染)。
  1. # 主页显示所有页面前端信息
  2. @app.route('/index', methods=['GET', 'POST'])
  3. def index():
  4. if request.method == 'POST':
  5. # 从ajax请求中取参数selected_version 取不到则为null
  6. version_text = request.form.get("selected_version", "null")
  7. else:
  8.         version_text = 'Syf1.1.1'
  9. g.db = sqlite3.connect(config.db_dir)
  10.     all_page_load_data = {}
  11.     page_time_detail = []
  12. # 从数据库中查询所有页面汇总信息
  13. for value in ['direct', 'domReady', 'loadEvent', 'request', 'ttfb', 'loadPageAll', 'name']:
  14.         sql = 'select ' + value + " from webLoad where project='" + str(version_text) + "'" + ' order by name'
  15. current_data = g.db.execute(sql).fetchall()
  16.         current_list = []
  17. if value == 'name':
  18. for data in current_data:
  19.                 current_list.append(str(data).strip("(u'").strip("',)"))
  20.             all_page_load_data[value] = current_list
  21. else:
  22. for data in current_data:
  23.                 current_list.append(int(str(data).strip('(').strip(')').split(',')[0]))
  24.             all_page_load_data[value] = current_list
  25. # 查询每个页面的时间详细
  26. page_detail_sql = "select name, url, loadEvent, domReady, request, ttfb, 0 as request_count, 0 as request_size " \
  27. "from webLoad where project='" + str(version_text) + "'" + ' order by name'
  28. page_detail_data = g.db.execute(page_detail_sql).fetchall()
  29. for data in page_detail_data:
  30.         page = {}
  31.         page['name'] = data[0]
  32.         page['url'] = data[1]
  33.         page['loadEvent'] = data[2]
  34.         page['domReady'] = data[3]
  35.         page['request'] = data[4]
  36.         page['ttfb'] = data[5]
  37.         page['request_count'] = data[6]
  38.         page['request_size'] = data[7]
  39.         page_time_detail.append(page)
  40.     g.db.close()
  41. return render_template("index.html", all_page_load_data=all_page_load_data, page_time_detail=page_time_detail)

复制代码




作者: lsekfe    时间: 2020-4-15 14:05
咦?这里我们貌似引入了一个新词模板,没错flask中使用Jinja作为模板。
我们一起来看下Jinja中一些常用知识点。
  1. <font color="black">0:表达式
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
  3. <htmllang="en">
  4. <head>
  5. <title>My Webpage</title>
  6. </head>
  7. <body>
  8. <ulid="navigation"> {% for item in navigation %}
  9. <li><ahref="{{ item.href }}">{{ item.caption }}</a></li>
  10. {% endfor %} </ul>
  11. <h1>My Webpage</h1> {{ a_variable }}
  12. </body>
  13. </html></font>
复制代码
两种分隔符{% … %} 和 {{ … }}. 前者用于执行表达式, 后者打印表达式的结果.

  1. 1.变量
  2. #这两种表达方式是一样的,如果属性不存在默认的设置是返回空字符串
  3. {{ foo.bar }}{{ foo['bar']}}
  4. 2.Filters(过滤器,我们也可以自定义过滤器)
  5. 对变量操作的函数,以|的形式写在后面
  6. #几个例子
  7. 1.        attr(obj, name)
  8. foo|attr("bar")<=>(等价于) foo["bar"]

  9. 2.batch(value, linecount, fill_with=None)
  10. #从左边取3个值,fill_with为不够的情况下的填充值
  11. {%-for row in items|batch(3,' ')%}

  12. 4.注释Comments
  13. #写在{# ... #}之间
  14. {# note: disabled template because we no longer usethis
  15. {%for user in users %}...{% endfor %}#}
  16. 5.空白 whitespace control
  17. 1.没有配置trim_blocks 和 lstrip_blocks
  18. <div>{%ifTrue%} yay {% endif %}</div> -><div> yay </div>
  19. 2.        配置了 trim_blocks 和 lstrip_blocks
  20. <div> yay </div>
  21. 3.        手动开启lstrip_blocks
  22. <div> {%+ if something %}yay{% endif %} </div>
  23. 4.        手动删除空白
  24. {%for item in seq -%}{{ item }}{%- endfor %}
  25. 6.转换符Escaping
  26. # 使用{{}} ,或者raw block {% raw %}
  27. {{'{{'}}{% raw %}<ul>{%for item in seq %}<li>{{ item }}</li>
  28. {% endfor %}</ul>{% endraw %}
  29. 7.Line Statements
  30. 配置后可以mark a line as a statement
  31. # for item in seq:
  32. <li>{{ item }}</li>## this comment is ignored
  33. # endfor
  34. 这种方法同{%for item in seq %}<li>{{ item }}</li>{% endfor %}
  35. 8.模板继承 Template Inheritance
  36. #1.父类模板 Template
  37. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
  38. <html lang="en"><html xmlns="http://www.w3.org/1999/xhtml">
  39. <head>{% block head %}
  40. <link rel="stylesheet" href="style.css"/>
  41. <title>{% block title %}{% endblock %}-MyWebpage</title>
  42. {% endblock %}
  43. </head>
  44. <body><div id="content">{% block content %}{% endblock %}</div>
  45. <div id="footer">{% block footer %}&copy;Copyright2008by<a href="http://domain.invalid/">you</a>. {% endblock %} </div>
  46. </body>
复制代码
2.子类模板继承Child Template
  1. {% extends "base.html" %}
  2. {% block title %}Index{% endblock %}
  3. {% block head %} {{ super() }}
  4. <style type="text/css"> .important { color: #336699; } </style> {% endblock %} {% block content %} <h1>Index</h1>
  5. <p class="important"> Welcome on my awesome homepage. </p> {% endblock %}
复制代码


3.还可以用self,引用block的变量
  1. <title>{% block title %}{% endblock %}</title>
  2. <h1>{{ self.title() }}</h1> {% block body %}{% endblock %}
复制代码
Super Blocks 引用parent block的内容
  1. {% block sidebar %} <h3>Table Of Contents</h3> ... {{ super() }} {% endblock %}
复制代码


5.block 结束符也可以加上名字
  1. {% block sidebar %} {% block inner_sidebar %} ...
  2. {% endblock inner_sidebar %}
  3. {% endblock sidebar %}
复制代码
6.block中的变量引用

  1. {% for item in seq %} <li>{% block loop_item %}{{ item }}{% endblock %}</li> # 打印为空,因为block内部不能引用外面的item变量 {% endfor %}
  2. 需要改变为 {% for item in seq %} <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li> {% endfor %}
复制代码

  1. 7.If a template object was passed to the template context you can extend from that object as well {% extends layout_template %}
复制代码

Jinja2模板的用法非常多,我们只需要掌握常用的即可,遇到不会的直接去官网搜吧。
下面贴上我这边Index.html页面源码中所用到的Jinja:
基类模板内容:
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5.         <title>{% block title %} {% endblock %}</title>
  6.         <link rel="stylesheet" type="text/css" href="../static/css/bootstrap.min.css">
  7.         <script src="../static/js/jquery.min.js"></script>
  8.         <script type="text/javascript" src="../static/js/echarts-all.js"></script>
  9.         <script type="text/javascript" src="../static/js/bootstrap.js"></script>
  10.         <script type="text/javascript" src="../static/js/events.js"></script>
  11.         {% block head %}{% endblock %}
  12. </head>

  13. <body>
  14.         <nav class="navbar text-info" role="navigation">
  15.         <ul class="nav nav nav-tabs panel-title">
  16.                         <li class="dropdown">
  17.                                 <a class="dropdown-toggle" data-toggle="dropdown" href="#">前端性能<b class="caret"></b></a>
  18.                                 <ul class="dropdown-menu">
  19.                                         <li><a href="/index">Clinical项目</a></li>
  20.                                         <li><a href="#">GeStorage项目</a></li>
  21.                                         <li><a href="#">Training项目</a></li>
  22.                                         <li><a href="#">PerformanceTiming学习</a></li>
  23.                                 </ul>
  24.                         </li>
  25.                         <li class="dropdown">
  26.                                 <a class="dropdown-toggle" data-toggle="dropdown" href="#">UI自动化测试<b class="caret"></b></a>
  27.                                 <ul class="dropdown-menu">
  28.                                         <li><a href="ui_auto">Clinical项目</a></li>
  29.                                         <li><a href="ui_auto">GeStorage项目</a></li>
  30.                                         <li><a href="ui_auto">Training项目</a></li>
  31.                                         <li><a href="ui_auto">RobotFrame知识库</a></li>
  32.                                         <li><a href="ui_auto">UI自动化脚本设计</a></li>
  33.                                 </ul>
  34.                         </li>
  35.                         <li class="dropdown">
  36.                                 <a class="dropdown-toggle" data-toggle="dropdown" href="#">接口自动化测试<b class="caret"></b></a>
  37.                                 <ul class="dropdown-menu">
  38.                                         <li><a href="service_auto">Clinical项目</a></li>
  39.                                         <li><a href="service_auto">GeStorage项目</a></li>
  40.                                         <li><a href="service_auto">Training项目</a></li>
  41.                                         <li><a href="#">接口测试知识库</a></li>
  42.                                 </ul>
  43.                         </li>
  44.                         <li class="dropdown">
  45.                                 <a class="dropdown-toggle" data-toggle="dropdown" href="#">兼容性自动化测试<b class="caret"></b></a>
  46.                                 <ul class="dropdown-menu">
  47.                                         <li><a href="#">Clinical项目</a></li>
  48.                                         <li><a href="#">GeStorage项目</a></li>
  49.                                         <li><a href="#">Training项目</a></li>
  50.                                         <li><a href="#">兼容性实施原理</a></li>
  51.                                 </ul>
  52.                         </li>
  53.                         <li class="dropdown">
  54.                                 <a class="dropdown-toggle" data-toggle="dropdown" href="#">性能测试<b class="caret"></b></a>
  55.                                 <ul class="dropdown-menu">
  56.                                         <li><a href="#">Clinical项目</a></li>
  57.                                         <li><a href="#">GeStorage项目</a></li>
  58.                                         <li><a href="#">Training项目</a></li>
  59.                                         <li><a href="#">性能测试实施细则</a></li>
  60.                                 </ul>
  61.                         </li>
  62.                         <li><a href="per_auto">全局变量配置</a></li>
  63.         </ul>

  64.         </nav>

  65. <div id="content" class="container">
  66.                 {% block content %}
  67.                 {% endblock %}
  68. </div>

  69. </body>
  70. </html>
复制代码
我这边index.html内容如下:
{% extends "base.html" %} //继承基类模板


  1. {% block title %}平台主页{% endblock %}
  2. {% block content %}
  3. <div class="row">
  4.         <label>项目版本</label>
  5.         <select id="project_version" onchange="optionChange()">
  6.                         {% for option in project_version.Clinical %}
  7.                 <option value={{option}}>{{option}}</option>
  8.                         {% endfor %}
  9.         </select>
  10.         <button id="redo" onClick="ajaxReRun()">重新执行</button>
  11. </div>
  12. <br>
  13. <table id="pages_summary" class="table table-hover">
  14.         <th>页面名称</th>
  15.         <th>页面URL</th>
  16.         <th>DNS耗时</th>
  17.         <th>Request耗时</th>
  18.                 <th>解析DOM耗时</th>
  19.         <th>DomReady耗时</th>
  20.         <th>LoadEvent耗时</th>
  21.         <th>白屏时长</th>
  22.         <th>整个页面加载耗时</th>
  23.                 {% for page in page_load_result %} //Jinja中的循环体
  24.         <tr class="active hover">
  25.                 <td class="active"><a href="javascript:{{page.page_name}}()">{{page.page_name}}</a></td>
  26.                         <script type="text/javascript">
  27.                                 function {{page.page_name}}()
  28.                                 {
  29.                                         var href = $('#project_version').get(0).selectedOptions[0].text + "_" +"{{page.page_name}}";
  30.                                         location.href = href
  31.                                 }
  32.                         </script>
  33.                 <td class="active">{{page.url}}</td>
  34.                         <td class="active">{{page.dns}}</td>
  35.                 <td class="active">{{page.request}}</td>
  36.                         <td class="active">{{page.dom_parser}}</td>
  37.                 <td class="active">{{page.dom_ready}}</td>
  38.                 <td class="active">{{page.load_event}}</td>
  39.                 <td class="active">{{page.whitewait}}</td>
  40.                 <td class="active">{{page.loadall}}</td>
  41.         </tr>
  42.                 {% endfor %} //Jinja中循环体的结束标识
  43. </table>
  44.         <br><br>
  45. <h4>所有页面加载数据统计堆叠图</h4>
  46.         <div id="page_summary_chart">
  47.         <table id="data_chart" width="100%">
  48.         <tr>
  49.                 <td align="center">
  50.                 <div id="chart" class="text-align:center" style="width: 1250px;height:650px;">
  51.                                 <script type="text/javascript">
  52.                                 // 基于准备好的dom,初始化echarts实例
  53.                                 var myChart = echarts.init(document.getElementById('chart'));

  54.                                 // 指定图表的配置项和数据
  55.                                 option = {
  56.                                     tooltip : {
  57.                                         trigger: 'axis',
  58.                                         axisPointer : {type : 'shadow'}
  59.                                     },
  60.                                     legend: {
  61.                                         data:['dns(ms)', 'request(ms)', 'dom_parser(ms)', 'dom_ready(ms)', 'load_event(ms)', 'whitewait(ms)', 'loadall(ms)'],
  62.                                     },
  63.                                     toolbox: {
  64.                                         show : true,
  65.                                         feature : {
  66.                                             mark : {show: true},
  67.                                             dataView : {show: true, readOnly: false},
  68.                                             magicType : {show: true, type: ['line', 'bar', 'stack', 'tiled']},
  69.                                             restore : {show: true},
  70.                                             saveAsImage : {show: true}
  71.                                         }
  72.                                     },
  73.                                     calculable : true,
  74.                                     xAxis : [
  75.                                         {
  76.                                             type : 'value'
  77.                                         }
  78.                                     ],
  79.                                     yAxis : [
  80.                                         {
  81.                                             type : 'category',
  82.                                             data :  {{page_chart_data.page_name|safe}}
  83.                                         }
  84.                                     ],
  85.                                     series : [
  86.                                         {
  87.                                             name:'dns(ms)',
  88.                                             type:'bar',
  89.                                             stack: 'Time',
  90.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  91.                                             data: {{page_chart_data.dns|safe}}
  92.                                         },

  93.                                         {
  94.                                             name:'request(ms)',
  95.                                             type:'bar',
  96.                                             stack: 'Time',
  97.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},

  98.                                             data: {{page_chart_data.request|safe}}
  99.                                         },

  100.                                         {
  101.                                             name:'dom_parser(ms)',
  102.                                             type:'bar',
  103.                                             stack: 'Time',
  104.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  105.                                             data: {{page_chart_data.dom_parser|safe}}
  106.                                         },

  107.                                         {
  108.                                             name:'dom_ready(ms)',
  109.                                             type:'bar',
  110.                                             stack: 'Time',
  111.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  112.                                             data: {{page_chart_data.dom_ready|safe}}
  113.                                         },

  114.                                         {
  115.                                             name:'request(ms)',
  116.                                             type:'bar',
  117.                                             stack: 'Time',
  118.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  119.                                             data: {{page_chart_data.request|safe}}
  120.                                         },

  121.                                       {
  122.                                             name:'load_event(ms)',
  123.                                             type:'bar',
  124.                                             stack: 'Time',
  125.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  126.                                             data: {{page_chart_data.load_event|safe}}
  127.                                         },
  128.                                         {
  129.                                             name:'whitewait(ms)',
  130.                                             type:'bar',
  131.                                             stack: 'Time',
  132.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  133.                                             data: {{page_chart_data.whitewait|safe}}
  134.                                         },
  135.                                         {
  136.                                             name:'loadall(ms)',
  137.                                             type:'bar',
  138.                                             stack: 'Time',
  139.                                             itemStyle : { normal: {label : {show: true, position: 'insideRight'}}},
  140.                                             data: {{page_chart_data.loadall|safe}}
  141.                                         }
  142.                                     ]
  143.                                         };
  144.                                 // 使用刚指定的配置项和数据显示图表。
  145.                                 myChart.setOption(option);
  146.                         </script>
  147.                         </div>
  148.                         </td>
  149.                 </tr>
  150.         </table>
  151.         </div>
  152. {% endblock %}
  153. (PS:在一个表格中循环查询到的结果并输出到页面)
复制代码

下面贴出来我这边views.py文件里的全部内容供同学们参考:
  1. # -*- coding:utf-8 -*-

  2. import sqlite3
  3. import sys
  4. import time

  5. import requests
  6. from flask import render_template, g, redirect, url_for, request, send_file
  7. from selenium import webdriver

  8. import config
  9. from Web import web_app

  10. reload(sys)
  11. sys.setdefaultencoding("utf-8")


  12. # 定义根路由
  13. @web_app.route('/')
  14. def root():
  15.     return render_template('login.html')


  16. @web_app.route('/login_success')
  17. def login_success():
  18.     return render_template('login_success.html')


  19. # 定义路由index
  20. @web_app.route('/index', methods=['GET', 'POST'])
  21. def index():
  22.     if request.method == 'POST':
  23.         version = request.form.get("selected_version", "null")
  24.     else:
  25.         version = 'syf1.1.1'
  26.     g.db = sqlite3.connect(config.db_dir)
  27.     summary_data_sql = 'select page_name, url, dns, request, dom_parser, dom_ready, load_event, whitewait, loadall '\
  28.                        + " from WebLoad where version='" + str(version) + "'" + ' order by page_name'
  29.     page_load_result = query_db(summary_data_sql)
  30.     g.db.close()
  31.     project_version = config.project_version_info
  32.     # 将页面信息转换为Echarts使用的数据
  33.     page_chart_data = {}
  34.     page_name_list = []
  35.     page_dns_list = []
  36.     page_request_list = []
  37.     page_dom_parser_list = []
  38.     page_dom_ready_list = []
  39.     page_load_event_list = []
  40.     page_whitewait_list = []
  41.     page_loadall_list = []
  42.     for result in page_load_result:
  43.         page_name_list.append(str(result['page_name']).strip("u'"))
  44.         page_dns_list.append(result['dns'])
  45.         page_request_list.append(result['request'])
  46.         page_dom_parser_list.append(result['dom_parser'])
  47.         page_dom_ready_list.append(result['dom_ready'])
  48.         page_load_event_list.append(result['load_event'])
  49.         page_whitewait_list.append(result['whitewait'])
  50.         page_loadall_list.append(result['loadall'])
  51.     page_chart_data['page_name'] = page_name_list
  52.     page_chart_data['dns'] = page_dns_list
  53.     page_chart_data['request'] = page_request_list
  54.     page_chart_data['dom_parser'] = page_dom_parser_list
  55.     page_chart_data['dom_ready'] = page_dom_ready_list
  56.     page_chart_data['load_event'] = page_load_event_list
  57.     page_chart_data['whitewait'] = page_whitewait_list
  58.     page_chart_data['loadall'] = page_loadall_list
  59.     return render_template('index.html', project_version=project_version, page_load_result=page_load_result, page_chart_data=page_chart_data)


  60. # 定义重新执行脚本的路由
  61. @web_app.route('/redo', methods=['GET', 'POST'])
  62. def redo():
  63.     if request.method == 'GET':
  64.         return 'route does not support get'
  65.     else:
  66.         # 向测试环境发生get请求来验证测试环境是否存在
  67.         env_for_test = request.form.get("selected_version", "null")
  68.         current_env = config.hosts['164'] + env_for_test
  69.         env_test_code = requests.get(current_env).status_code
  70.         if env_test_code == 200:
  71.             # 定义页面名称列表
  72.             all_page_data = {}
  73.             page_urls = config.page_urls
  74.             timing_js = config.timing_js

  75.             # 统计页面加载时间的6个维度登录页专用
  76.             index_data = {'dns': 0, 'request': 0, 'dom_parser': 0, 'dom_ready': 0, 'load_event': 0, 'whitewait': 0, 'loadall': 0}
  77.             # index页面资源的信息登录页专用
  78.             page_index_info = []
  79.             # 将统计数据保存到sqlite
  80.             connection = sqlite3.connect(config.db_dir)
  81.             cursor = connection.cursor()
  82.             # 先删除页面资源细分表webDetailLoad所有数据
  83.             clear_resource_sql = "delete from PageDetail where project='Clinical' and version='" + env_for_test + "'"
  84.             cursor.execute(clear_resource_sql)
  85.             # 先清理上次的数据
  86.             clear_webload_sql = "delete from WebLoad where project='Clinical' and version='" + env_for_test + "'"
  87.             cursor.execute(clear_webload_sql)
  88.             connection.commit()
  89.             # get到clinical登录页(登录页需要单独收集其页面加载性能指标)
  90.             driver = webdriver.Chrome()
  91.             login_url = current_env + '/login/index'
  92.             driver.get(login_url)
  93.             driver.maximize_window()
  94.             time.sleep(5)
  95.             time_line = driver.execute_script(config.timing_js)
  96.             # 将页面加载时间存入all_page_data
  97.             for key in index_data.keys():
  98.                 index_data[key] = time_line[key]
  99.             # 将index的数据存入all_page_data
  100.             all_page_data['Index'] = index_data

  101.             # 获得index页面所有的资源实体
  102.             entries = driver.execute_script(config.get_entries_js)
  103.             # 遍历登录页面所有资源
  104.             for items in entries:
  105.                 # 以页面名:数组形式保存页面信息
  106.                 page_index_resource = {}
  107.                 # 资源名称
  108.                 page_index_resource['name'] = items['name']
  109.                 # 资源类型分类
  110.                 resource_type = str(items['name']).split('.')[-1]
  111.                 if resource_type in ['jpg', 'png', 'gif', 'jpeg']:
  112.                     page_index_resource['resourceType'] = 'img'
  113.                 elif resource_type == 'js':
  114.                     page_index_resource['resourceType'] = 'js'
  115.                 elif resource_type == 'css':
  116.                     page_index_resource['resourceType'] = 'css'
  117.                 else:
  118.                     if items['initiatorType'] == 'xmlhttprequest':
  119.                         page_index_resource['resourceType'] = 'xmlhttprequest'
  120.                     elif items['initiatorType'] == 'script':
  121.                         page_index_resource['resourceType'] = 'js'
  122.                     else:
  123.                         page_index_resource['resourceType'] = 'other'
  124.                 # 资源大小
  125.                 page_index_resource['transferSize'] = items['transferSize']
  126.                 # 资源耗时
  127.                 page_index_resource['duration'] = items['duration']
  128.                 # 将登录页资源信息存入列表
  129.                 page_index_info.append(page_index_resource)
  130.                 # 将登录页资源列表信息存入字典对象对应key为Index
  131.                 save_resource_sql = 'insert into PageDetail ' + "values('Clinical','" + str(env_for_test) + "'," + "'" + str(
  132.                     'Index') + "'," + "'" + str(page_index_resource['name']) + "'," + "'" + str(
  133.                     page_index_resource['resourceType']) + "'," + "'" \
  134.                                     + str(page_index_resource['transferSize']) + "'," + "'" + str(
  135.                     page_index_resource['duration']) + "'," + 'CURRENT_TIMESTAMP)'
  136.                 cursor.execute(save_resource_sql)
  137.                 connection.commit()
复制代码



作者: lsekfe    时间: 2020-4-15 14:10
具体内容请查看。





作者: szc123qq    时间: 2020-5-18 10:49





欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2