# 易大师前端网页性能测试框架 **Repository Path**: xuwangcheng/ppts-selenium ## Basic Information - **Project Name**: 易大师前端网页性能测试框架 - **Description**: 基于selenium的前端网页性能测试框架 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 3 - **Created**: 2021-11-06 - **Last Updated**: 2024-06-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PPTS-selenium 基于Selenium的前端网页性能测试框架 ### 开始使用 #### 准备工作 1. 电脑上安装了Python3.6+以上版本 2. 配置国内PIP源:https://www.cnblogs.com/songzhixue/p/11296720.html; 3. 电脑安装了60+以上版本的Chrome,不要太老也不要太新; 4. 下载安装chromedriver.exe:http://npm.taobao.org/mirrors/chromedriver,chrome与chromedriver的版本要对应上,可以参考https://blog.csdn.net/qq_38316655/article/details/112752328,下载好了将chromedriver.exe放到python的安装目录下; #### 下载代码 前往gitee下载最新代码: 下载之后,解压,双机 _pipInstall.cmd_ 安装依赖,安装失败的话,可以手动在该目录下打开cmd目录,执行命令*pip install -r requirements.txt* ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114140_d76b3442_431003.png "屏幕截图.png") #### 编写配置文件 工具目录下已经写了一个config.yaml的示例测试配置: ```yaml browser_type: chrome no_headless: false cache: false repeat: 1 test_interval_time: 1 page_load_timeout: 30 report_name: 前端页面性能测试 report_type: html pass_time: 4000 challenge_time: 3000 test_urls: - script: LoginDtmp - url: 'https://dtmp.xuwangcheng.com/#/workbench-home' spa: true check_element: by_type: xpath by_value: '//*[@id="pane-workbench-home"]/div/div[4]/div/div/div[2]/div[8]/div[1]/p' - url: 'https://dtmp.xuwangcheng.com/#/infrastructure-env-env' spa: true check_element: by_type: xpath by_value: '//*[@id="pane-infrastructure-env-env"]/div/div/div/div[1]/div[3]/table/tbody/tr[10]/td[3]/div/a' - url: 'https://www.xuwangcheng.com' tab: 2 ``` #### 测试执行 在当前目录打开cmd窗口,执行命令*python start.py*开始执行测试,执行过程中会自动打开chrome浏览器,测试完成之后会自动关闭,测试完成之后,在result下打开最后一个目录,里面会有本次测试生成的html报告,打开查看。 > python start.py默认使用的是config.yaml配置文件,如果你想要使用不同的配置文件进行测试,你可以使用python start.py xxxx.yaml来执行测试 ### 配置文件 #### 配置文件示例 ```yaml # 开始要执行的脚本,登陆,初始化可以放在这里面做,只会执行一次 # start_script: login # 结束时要执行的脚本,还原,处理结果数据等可以放在这里做,只会执行一次 # complete_script: end # 要运行的浏览器类型 browser_type: chrome # 对应浏览器的驱动path,如不填,则需要配置到环境变量中去 # driver_path: E:/aaaa/driver.exe # 是否开启无头模式,开启无头模式将不会显示GUI执行界面 no_headless: false # 是否开启缓存,在每次重复执行的时候 cache: false # 生成的报告文件名称,若不填写,则以时间戳命名 report_name: 前端页面性能测试 # 最终生成的报告类型,支持同时生成多种类型:html, json, csv, excel(尚未实现) report_type: html # 达标值,ms pass_time: 4000 # 挑战值,ms challenge_time: 3000 # 重复测试的次数 repeat: 5 # 每次测试的时候间隔时间 test_interval_time: 1 # 等待页面加载完成的超时时间,默认30s page_load_timeout: 30 # 要测试的url,将会按照顺序去执行 test_urls: # name: 为链接的自定义名称,若不填,则默认去网页标题 - name: 订单页面1 # 对应访问的url地址 url: 'https://dtmp.xuwangcheng.com' # 是否需要截图 screenshot: false # 达标值,ms,该处配置会覆盖全局配置 pass_time: 4000 # 挑战值,ms,该处配置会覆盖全局配置 challenge_time: 3000 - name: 订单页面2 # 对应访问的url地址 url: 'https://www.xuwangcheng.com' - name: 订单页面3 # 需要自定义去处理该url,去访问的脚本:主要对一些复杂的需要业务操作,业务数据,可以在脚本中记录性能数据 script: TestScriptSample # 表明当前是否需要收集性能数据,默认为true,设置为false的话,将不会收集数据也不会显示到报告中去 collect_data: false - script: LoginDtmp - url: 'https://dtmp.xuwangcheng.com/#/infrastructure-env-env' # 标识是否为单页面应用,如果为spa单页面应用,将会使用自定义的方式来计算加载时间 spa: true # 对于单页面应用,应该要设置一个检查元素,用以标识页面加载完成 check_element: # 支持xpath,name,id,tag name,class name,css selector,link text by_type: xpath # 对应的定位值 by_value: '//*[@id="pane-infrastructure-env-env"]/div/div/div/div[1]/div[3]/table/tbody/tr[10]/td[3]/div/a' - url: 'https://www.xuwangcheng.com' # 如果有多个tab页,就切换到指定index的tab(从左到右,从1开始),接下来的操作将都会在这个窗口进行 tab: 2 ``` #### 配置属性介绍 配置相关的属性说明都已经写在了config_sample.yaml文件中,下面只对比较重要的属性进行介绍: - **no_headless** 配置此属性为true,将会开启浏览器的无头模式,此模式下将不会显示浏览器的GUI界面,但是不影响正常的网页请求和加载 - **cache** 配置此属性为true,将会启用缓存,这会导致对相同的网页除了第一次测试,后续的重复测试将会使用缓存访问 - **test_interval_time** 访问单个URL或者执行单个自定义脚本之间的间隔时间,单位为秒 - **page_load_timeout** 页面完整加载完成的超时等待时间,超时了也只会导致本条URL本次测试失败,不会中止整个测试流程 - **test_urls.screenshot** 配置执行单条URL测试是否需要截图,目前截图仅可以在result结果目录下查看,还没有其他用途 - **test_urls.script** 配置自定义的脚本,脚本需要编写在busi.script目录下,只需要写脚本名称,不用加.py后缀,而且脚本中必须有 def to_exec(driver=None)方法,配置的script属性优先级高于配置的url属性,即同时配置了url和script属性,优先执行script - **test_urls.collect_data** 表示当前要访问的url或者要执行的脚本,是否需要收集性能测试,用于一些中间操作,跳转,前置操作等等,不会显示在测试报告中; - **test_url.tab** 用于切换多窗口,tab为窗口索引,从1开始 ### 测试报告 #### 报告类型 目前支持json,csv,html三种类型的测试报告,可以在配置文件里配置report_type来确定最终生成的报告类型: #### JSON ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114211_88274f28_431003.png "屏幕截图.png") #### CSV ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114218_8098576b_431003.png "屏幕截图.png") #### HTML ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114226_832e6970_431003.png "屏幕截图.png") #### 完整的测试性能数据 ```json { "report_name": "前端页面性能测试", "browser_type": "chrome", "no_headless": "False", "pass_time": 4000, "challenge_time": 3000, "repeat": 3, "cache": "False", "page_load_timeout": 30, "start_time": "2021-11-05 17:16:13", "complete_time": "2021-11-05 17:17:56", "use_time": 103426, "data": [{ "is_pass": "False", "pass_time": 4000, "is_challenge": "False", "challenge_time": 3000, "name": "订单页面1", "url": "https://dtmp.xuwangcheng.com", "total_count": 3, "request_time": { "max": 183, "min": 147, "avg": 160, "list": [147, 150, 183] }, "redirect_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "domain_lookup_time": { "max": 1, "min": 0, "avg": 0, "list": [0, 1, 0] }, "connect_time": { "max": 518, "min": 333, "avg": 439, "list": [467, 333, 518] }, "dom_render_time": { "max": 16247, "min": 12411, "avg": 14688, "list": [12411, 16247, 15407] }, "blank_screen_time": { "max": 911, "min": 489, "avg": 702, "list": [911, 489, 708] }, "page_load_time": { "max": 16740, "min": 13326, "avg": 15395, "list": [13326, 16740, 16119] }, "test_list": [{ "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 147, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 467, "dom_render_time": 12411, "blank_screen_time": 911, "page_load_time": 13326, "start_time": "2021-11-05 17:16:18", "use_time": 13335 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 150, "redirect_time": 0, "domain_lookup_time": 1, "connect_time": 333, "dom_render_time": 16247, "blank_screen_time": 489, "page_load_time": 16740, "start_time": "2021-11-05 17:16:51", "use_time": 16757 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 183, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 518, "dom_render_time": 15407, "blank_screen_time": 708, "page_load_time": 16119, "start_time": "2021-11-05 17:17:29", "use_time": 16133 }], "success_count": 1 }, { "is_pass": "False", "pass_time": 4000, "is_challenge": "False", "challenge_time": 3000, "name": "云测试管理平台", "url": "https://www.xuwangcheng.com", "total_count": 3, "request_time": { "max": 484, "min": 163, "avg": 299, "list": [163, 252, 484] }, "redirect_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "domain_lookup_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "connect_time": { "max": 352, "min": 242, "avg": 279, "list": [244, 352, 242] }, "dom_render_time": { "max": 9352, "min": 4419, "avg": 7158, "list": [7705, 9352, 4419] }, "blank_screen_time": { "max": 729, "min": 493, "avg": 610, "list": [493, 608, 729] }, "page_load_time": { "max": 10005, "min": 5190, "avg": 7806, "list": [8224, 10005, 5190] }, "test_list": [{ "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 163, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 244, "dom_render_time": 7705, "blank_screen_time": 493, "page_load_time": 8224, "start_time": "2021-11-05 17:16:32", "use_time": 8250 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 252, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 352, "dom_render_time": 9352, "blank_screen_time": 608, "page_load_time": 10005, "start_time": "2021-11-05 17:17:09", "use_time": 10025 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 484, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 242, "dom_render_time": 4419, "blank_screen_time": 729, "page_load_time": 5190, "start_time": "2021-11-05 17:17:47", "use_time": 5208 }], "success_count": 1 }, { "is_pass": "True", "pass_time": 4000, "is_challenge": "False", "challenge_time": 3000, "name": "百度搜索", "url": "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=selenium&fenlei=256&rsv_pq=9ff5f0c90000ee6a&rsv_t=b7feiOqUD5HVJYCdgaN%2FQS%2B9w7PVulNbiQ4DP1C%2B1tRJCYiSXP6tnu%2BVfmM&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=8&rsv_btype=i&inputT=138&rsv_sug4=138", "total_count": 3, "request_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "redirect_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "domain_lookup_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "connect_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "dom_render_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "blank_screen_time": { "max": 0, "min": 0, "avg": 0, "list": [0, 0, 0] }, "page_load_time": { "max": 3672, "min": 2999, "avg": 3333, "list": [2999, 3330, 3672] }, "test_list": [{ "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 0, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 0, "dom_render_time": 0, "blank_screen_time": 0, "page_load_time": 2999, "start_time": "2021-11-05 17:16:41", "use_time": 3007 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 0, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 0, "dom_render_time": 0, "blank_screen_time": 0, "page_load_time": 3330, "start_time": "2021-11-05 17:17:20", "use_time": 3330 }, { "success": "True", "error_msg": "", "screenshot_path": "", "request_time": 0, "redirect_time": 0, "domain_lookup_time": 0, "connect_time": 0, "dom_render_time": 0, "blank_screen_time": 0, "page_load_time": 3672, "start_time": "2021-11-05 17:17:53", "use_time": 3672 }], "success_count": 1 }], "url_count": 3 } ``` #### 自定义扩展报告 如果你想要自定义自己的测试报告,可以按照如下步骤编写代码: 1. 在 *ppts.core.ReportGenerate.py* 文件中新建一个方法,如下: ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114305_7d75c143_431003.png "屏幕截图.png") 其中两个参数分别为结果数据和报告文件的前缀: - **json_data**: 参考 完整的测试性能数据 中的示例,注意此处还只是字典类型,你可以通过json.dumps(json_data, sort_keys=False, indent=4, ensure_ascii=False)代码来序列化为JSON字符串(sort_keys表示是否需要排序key,ident表示是否需要格式化json,数字代表缩进的字符数, ensure_ascii表示是否要将中文转成ascii码); - **report_path**: 如果你要生成文件,最终生成的文件路径可以设置成:report_path = report_path + '.xlsx',你只需要加个文件后缀就行了。 2. 在 _ppts.entity.GlobalTestObject.py_ 文件中找到100-110行之间代码: ![](https://images.gitee.com/uploads/images/2021/1106/114352_811b8485_431003.png "屏幕截图.png") 你只需要加一个你自己的elif判断即可。 3. 在*config.yaml*配置文件中设置**report_type**为你新增的报告类型,测试完成之后,将会执行你扩展的自定义报告处理逻辑。 ### 自定义脚本 对于需要进行特殊的业务操作才能访问的页面,或者需要统计整个业务流程的耗时,你可以自行编写自定义脚本,并且配置到配置文件中即可, 脚本编写示例可以参考*busi.script*下的*TestScriptSample.py*脚本: ```python import logging from ppts.entity.PagePerformanceData import PagePerformanceData import time def to_exec(driver=None): # 通过logging打印日志 logging.info('访问URL=[https://www.baidu.com]') begin = time.time() # 自定义请求地址或者完成一系列的业务操作 driver.get('https://www.baidu.com') driver.find_element_by_id("kw").send_keys("selenium") driver.find_element_by_id("su").click() end = time.time() # 计算总耗时 毫秒 load_time = int(round((end - begin) * 1000)) # 自定义构件性能结果数据 data = PagePerformanceData() # 自行根据业务向其中放入性能数据,page_load_time代表整体的加载耗时,在此处表示整个业务流程的耗时 data.page_load_time = load_time # 返回性能数据 return data ``` ### 其他问题 #### 测试单页面应用 > Navigation Timing API可以监控大部分前端页面的性能。但随着SPA模式的盛行,类似vue,reactjs等框架的普及,页面内容渲染的时机被改变了,通过window.performance.timing所获的的页面渲染所相关的数据,在SPA应用中改变了url但不刷新页面的情况下是不会更新的。因此仅仅通过该api是无法获得每一个子路由所对应的页面渲染的时间。 如果需要测试单个SPA应用的不同路由页面的加载性能(实际上是Api请求和JS渲染页面的时间),需要在配置文件针对test_url节点中配置spa和check_element两个参数: - **spa参数**: 来标记当前测试的url是否为单页面应用的路由页面,如果设置为true,则会使用自定义方式来计算页面加载时间,而不是window.performance.timing方式。 - **check_element参数**: 通常spa的路由页面是不会改变浏览器url的,这会导致selenium无法得知页面是否已经切换或者加载完成,所以,需要配置一个检查元素,通过这个检查元素来标记页面加载完成。 #### 支持的浏览器? 目前仅支持Chrome浏览器,FireFox应该也可以,但是没有调试; #### 支持的应用平台? 仅支持Web网页,不支持安卓/IOSApp以及小程序等; #### 性能数据是否准确? 性能数据采集使用的是浏览器内置的performance工具统计出来的数据,可以参考:https://blog.csdn.net/weixin_43484977/article/details/103339233 ![](https://images.gitee.com/uploads/images/2021/1106/114545_4bef5777_431003.png "屏幕截图.png") ![输入图片说明](https://images.gitee.com/uploads/images/2021/1106/114557_45061e5a_431003.png "屏幕截图.png")