UI自动化测试框架搭建-标记性能较差用例
在拿到性能数据后需要将数据利用起来,下面对性能数据进行分析
实现:如果性能达到设定的阈值,那么这段时间执行的用例就是性能较差的用例
确定阈值
首先确定一个阈值来当做性能的告警值,暂定为以下算法
# threshold 阈值
# average 平均值
# max 最大值
threshold = average + (max - average) * 0.8
计算各项值
在上一章已经拿到了性能数据,然后把他们插入到数据库中
由于平台是Java的所以用Java编写
构造一个HashMap来存放全部的数据
Map<String, Map<String, List<Double>>> perfSummaryData = new HashMap<>();
最终返回的数据类型为:
{
"cpu":{"system":[363,25,121.43243243243244,314.6864864864865],"idle":[761,4,537.3716216216217,716.2743243243243],"pic_cpu":[373,3.2,66.42430555555556,311.6848611111111],"device_cpu_rate":[904,36,245.6418918918919,772.3283783783784],"user":[652,11,124.20945945945945,546.4418918918919]},
"mem":{"free_ram":[2707.73,1720.11,2044.2376923076922,2575.0315384615387],"pid_pss":[452.18,231.72,313.105,424.365],"total_ram":[5478.93,5478.93,5478.929999999999,5478.93]},"other":null,"power":{"current":[0,0,0,0],"tempreture":[36.8,29.9,33.69638554216868,36.17927710843373],"voltage":[4.34,4.13,4.284096385542169,4.328819277108433]},"pss":{"pssList":[],"java_heap":[],"pss_system":[],"native_heap":[]},"thread":{"threadList":[272,3,191.46308724832215,255.89261744966444]},"traffic":{"device_transport":[6283.15,433.69,3777.436774193548,5782.00735483871],"device_receive":[167860.62,11597.64,106851.58806451612,155658.81361290324],"device_total":[174143.77,12031.33,110629.02451612902,161440.8209032258],"pid_tx":[6283.15,474.8,3779.061612903226,5782.332322580645],"pid_total":[174143.71,13349.69,110675.72096774195,161450.11219354838],"pid_rx":[167860.55,12874.89,106896.65838709677,155667.77167741934]},"version":"微医用户版4.6.5-内部版本号:268-灰度-待发布-创建时间:2022-06-23 21:18:10-最近修改时间:2022-06-23 21:18:10"
}
依次解析每个版本每次执行的性能数据然后根据性能类型放到对应的List中
然后计算一下最大、最小、平均、阈值
floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).max().orElse(0.0));
floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).min().orElse(0.0));
floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).average().orElse(0.0));
floats.add(floats.get(2) + 0.8 * (floats.get(0) - floats.get(2))); // 阈值
完整代码
@Override
public List<UiPerfSummaryDo> getPerfDataSummary(UiPerfPageQuery pageQuery) {List<UiPerfDo> perfData = uiReportMapper.getPerfData(pageQuery);Map<String, Map<String, List<Double>>> perfSummaryData = new HashMap<>();String[] cpuKeys = { "device_cpu_rate", "user", "system", "idle", "pic_cpu" };String[] memKeys = { "total_ram", "free_ram", "pid_pss" };String[] powerKeys = { "voltage", "tempreture", "current" };String[] threadKeys = { "threadList" };String[] pssKeys = { "pssList", "java_heap", "native_heap", "pss_system" };String[] trafficKeys = { "device_total", "device_receive", "device_transport", "pid_rx", "pid_tx","pid_total" };String[][] allKeys = { cpuKeys, memKeys, powerKeys, threadKeys, pssKeys, trafficKeys };perfData.forEach(item -> {String version = item.getVersion();if (!perfSummaryData.containsKey(version)) {HashMap<String, List<Double>> perfVersion = new HashMap<>();for (String[] keys : allKeys) {for (String key : keys) {perfVersion.put(key, new ArrayList<>());}}perfSummaryData.put(version, perfVersion);}Map<String, List<Double>> stringListMap = perfSummaryData.get(version);List<String> cpus = JSONArray.parseArray(item.getCpu(), String.class);List<String> mems = JSONArray.parseArray(item.getMem(), String.class);List<String> powers = JSONArray.parseArray(item.getPower(), String.class);List<String> threads = JSONArray.parseArray(item.getThread(), String.class);List<String> psss = JSONArray.parseArray(item.getPss(), String.class);List<String> traffics = JSONArray.parseArray(item.getTraffic(), String.class);cpus.forEach(cpu -> {List<String> oneCpuInfo = JSONArray.parseArray(cpu, String.class);if (!oneCpuInfo.isEmpty()) {for (int i = 1; i < 6; i++) {List<Double> datalist = stringListMap.get(cpuKeys[i - 1]);datalist.add(Double.parseDouble(oneCpuInfo.get(i)));}}});mems.forEach(mem -> {List<String> oneMemInfo = JSONArray.parseArray(mem, String.class);if (!oneMemInfo.isEmpty()) {for (int i = 1; i < 4; i++) {List<Double> datalist = stringListMap.get(memKeys[i - 1]);datalist.add(Double.parseDouble(oneMemInfo.get(i)));}}});powers.forEach(power -> {List<String> onePowerInfo = JSONArray.parseArray(power, String.class);if (!onePowerInfo.isEmpty()) {for (int i = 1; i < 4; i++) {List<Double> datalist = stringListMap.get(powerKeys[i - 1]);datalist.add(Double.parseDouble(onePowerInfo.get(i)));}}});threads.forEach(thread -> {List<String> oneThreadInfo = JSONArray.parseArray(thread, String.class);if (!oneThreadInfo.isEmpty()) {for (int i = 1; i < 2; i++) {List<Double> datalist = stringListMap.get(threadKeys[i - 1]);datalist.add(Double.parseDouble(oneThreadInfo.get(i)));}}});psss.forEach(pss -> {List<String> onePssInfo = JSONArray.parseArray(pss, String.class);if (!onePssInfo.isEmpty()) {for (int i = 1; i < 5; i++) {List<Double> datalist = stringListMap.get(pssKeys[i - 1]);datalist.add(Double.parseDouble(onePssInfo.get(i)));}}});traffics.forEach(traffic -> {List<String> oneTrafficInfo = JSONArray.parseArray(traffic, String.class);if (!oneTrafficInfo.isEmpty()) {for (int i = 1; i < 7; i++) {List<Double> datalist = stringListMap.get(trafficKeys[i - 1]);datalist.add(Double.parseDouble(oneTrafficInfo.get(i)));}}});});List<UiPerfSummaryDo> uiPerfSummaryDos = new ArrayList<>();List<Double> floats;for (String key : perfSummaryData.keySet()) {UiPerfSummaryDo uiPerfSummaryDo = new UiPerfSummaryDo();Map<String, List<Double>> stringListMap = perfSummaryData.get(key);uiPerfSummaryDo.setVersion(key);for (String[] all_key : allKeys) {HashMap<String, List<Double>> dataDict = new HashMap<>();for (String key1 : all_key) {floats = new ArrayList<>();List<Double> floats1 = stringListMap.get(key1);if (!floats1.isEmpty()) {floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).max().orElse(0.0));floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).min().orElse(0.0));floats.add(floats1.stream().mapToDouble(e -> e).filter(e -> e > 0.0).average().orElse(0.0));floats.add(floats.get(2) + 0.8 * (floats.get(0) - floats.get(2))); // 阈值}dataDict.put(key1, floats);}if (Arrays.equals(all_key, cpuKeys)) {uiPerfSummaryDo.setCpu(dataDict);}if (Arrays.equals(all_key, memKeys)) {uiPerfSummaryDo.setMem(dataDict);}if (Arrays.equals(all_key, powerKeys)) {uiPerfSummaryDo.setPower(dataDict);}if (Arrays.equals(all_key, threadKeys)) {uiPerfSummaryDo.setThread(dataDict);}if (Arrays.equals(all_key, pssKeys)) {uiPerfSummaryDo.setPss(dataDict);}if (Arrays.equals(all_key, trafficKeys)) {uiPerfSummaryDo.setTraffic(dataDict);}}uiPerfSummaryDos.add(uiPerfSummaryDo);}return uiPerfSummaryDos;
}
解析Allure报告
拿到一个用例的开始时间和结束时间,方便确定用例执行的时间范围
在13.UI自动化测试框架搭建-处理Allure报告数据中有提到如何拿到allure的内容
data = {"fullName": full_name,"status": json_data.get("status"),"labels": labels,"start": json_data.get("start", 0),"stop": json_data.get("stop", 0),"duration": json_data.get("stop", 0) - json_data.get("start", 0),"parameters": parameters,"statusDetails": statusDetails1,"kano_url": ",".join(kano_url),"steps": ";".join(steps),"desc": ";"
}
添加了
"start": json_data.get("start", 0)
"stop": json_data.get("stop", 0)
"desc": ";"
现在将用例执行的情况写入到一份csv文件中,方便与其他的性能数据进行比对
# 拼接csv文件路径
casesfile = os.path.join(PERF_PATH, 'cases.csv')
# csv文件头部
title = ["datetime", "flag"] + list(allure_results[0].keys())
with open(casesfile, "a+", encoding="utf-8") as f:# 写入头部csv.writer(f, lineterminator='\n').writerow(title)for i in allure_results:allure_data1 = [timeoperator.get_localtime(i['start'], "%Y-%m-%d %H-%M-%S"), True] + list(i.values())allure_data2 = [timeoperator.get_localtime(i['stop'], "%Y-%m-%d %H-%M-%S"), False] + list(i.values())csv.writer(f, lineterminator='\n').writerow(allure_data1)csv.writer(f, lineterminator='\n').writerow(allure_data2)
使得datetime等于start和stop,写入两遍,再使用flag来标记方便后面去除掉
这样就得到一份按照时间排序的用例执行结果了
datetime,flag,fullName,status,labels,start,stop,duration,parameters,statusDetails,kano_url,steps,desc
2022-08-01 14-04-44,True,src.cases_android.wy.test_health.TestMedicationReminder#test_close_medication_reminder,passed,微医APP_健康_用药提醒-关闭用药提醒(@钟鑫),1659333884508,1659333917256,32748,,"{'message': '', 'trace': ''}",,1-查看提醒状态;1.1-查看「用药提醒_已开启提醒」是否存在;2-关闭用药提醒;2.1-点击「用药提醒_提醒滑块1」;3-点击确认;3.1-点击「通用_确认关闭」;4-查看提醒状态;4.1-查看「用药提醒_已关闭提醒」是否存在;4.2-查看「用药提醒_已关闭提醒1」是否存在;5-打开用药提醒;5.1-点击「用药提醒_提醒滑块2」;5.2-点击「用药提醒_已关闭提醒1」;6-查看提醒状态;6.1-查看「用药提醒_已开启提醒」是否存在,;
2022-08-01 14-05-17,False,src.cases_android.wy.test_health.TestMedicationReminder#test_close_medication_reminder,passed,微医APP_健康_用药提醒-关闭用药提醒(@钟鑫),1659333884508,1659333917256,32748,,"{'message': '', 'trace': ''}",,1-查看提醒状态;1.1-查看「用药提醒_已开启提醒」是否存在;2-关闭用药提醒;2.1-点击「用药提醒_提醒滑块1」;3-点击确认;3.1-点击「通用_确认关闭」;4-查看提醒状态;4.1-查看「用药提醒_已关闭提醒」是否存在;4.2-查看「用药提醒_已关闭提醒1」是否存在;5-打开用药提醒;5.1-点击「用药提醒_提醒滑块2」;5.2-点击「用药提醒_已关闭提醒1」;6-查看提醒状态;6.1-查看「用药提醒_已开启提醒」是否存在,;
2022-08-01 13-24-32,True,src.cases_android.wy.test_me.TestSetting#test_entrance_text,passed,微医APP_个人中心_设置-子项入口文案检查(@钟鑫),1659331472953,1659331473076,123,'settings_message',"{'message': '', 'trace': ''}",,1-查看是否存在我_设置-消息通知;1.1-查看「我_设置-消息通知」是否存在,;
2022-08-01 13-24-33,False,src.cases_android.wy.test_me.TestSetting#test_entrance_text,passed,微医APP_个人中心_设置-子项入口文案检查(@钟鑫),1659331472953,1659331473076,123,'settings_message',"{'message': '', 'trace': ''}",,1-查看是否存在我_设置-消息通知;1.1-查看「我_设置-消息通知」是否存在,;
数据比对
读取用例执行结果
读取文件后将它的datetimes设置为datetime类型,方便后面的排序
def cases_handle(self, path=f"{PERF_PATH}/cases.csv"):df = self.read_csv(path)df['datetime'] = pd.to_datetime(df['datetime'], format="%Y-%m-%d %H-%M-%S")df = df.sort_values("datetime", ascending=True)return df
编写比较函数
def add_desc(self, **kwargs) -> [dict]:...
**kwargs动态输入键值对来进行筛选
记录原先的列
base_title = list(cases_df.columns)
先进行cpu性能数据的处理
cpu = ['device_cpu_rate%', 'user%', 'system%', 'idle%', 'pid_cpu%']
遍历输入的键值对,如果输入的key值加上%在cpu这个列表里面,那就筛选出cpu性能数据中符合条件的数据
for k, v in kwargs.items():if f"{k}%" in cpu:name = f"{k}%"df1 = cpu_df[cpu_df[name] > v]
将两个表合并一下
cases_df = pd.concat([df1, cases_df]).sort_values("datetime", ascending=True)
拿到超过阈值的行号索引
error_index = list(cases_df[cases_df[name] > 0].index)
在超过阈值索引的附近几行添加描述
for i in error_index:cases_df.loc[i, 'desc'] += f"{k}超过阈值;"try:cases_df.loc[i - 1, 'desc'] += f"{k}超过阈值;"except Exception:passtry:cases_df.loc[i + 1, 'desc'] += f"{k}超过阈值;"except Exception:pass
剔除性能数据的列
cases_df = cases_df[pd.notnull(cases_df['fullName'])]
根据flag去除重复添加的用例信息
cases_df = cases_df[cases_df['flag'] == True]
根据之前保留的原始列信息将性能数据列去除
new_df = pd.DataFrame(cases_df, columns=base_title)
返回[dict]格式
return new_df.to_dict("records")
全部新增代码
def cases_handle(self, path=f"{PERF_PATH}/cases.csv"):df = self.read_csv(path)df['datetime'] = pd.to_datetime(df['datetime'], format="%Y-%m-%d %H-%M-%S")df = df.sort_values("datetime", ascending=True)return dfdef add_desc(self, **kwargs) -> [dict]:cpu = ['device_cpu_rate%', 'user%', 'system%', 'idle%', 'pid_cpu%']mem = ['total_ram(MB)', 'free_ram(MB)', 'pid_pss(MB)']power = ['voltage(V)', 'tempreture(C)', 'current(mA)']traffic = ['device_total(KB)', 'device_receive(KB)','device_transport(KB)','pid_rx(KB)', 'pid_tx(KB)', 'pid_total(KB)']cpu_df = self.cpu_handle()mem_df = self.mem_handle()power_df = self.power_handle()thread_df = self.thread_num_handle()traffic_df = self.traffic_handle()cases_df = self.cases_handle()base_title = list(cases_df.columns)for k, v in kwargs.items():if f"{k}%" in cpu:name = f"{k}%"df1 = cpu_df[cpu_df[name] > v]if f"{k}(MB)" in mem:name = f"{k}(MB)"df1 = mem_df[mem_df[name] > v]if any([f"{k}({i})" in power for i in ['V', 'C', 'mA']]):if k == "voltage":name = f"{k}(V)"df1 = power_df[power_df[name] > v]if k == "tempreture":name = f"{k}(C)"df1 = power_df[power_df[name] > v]if k == "current":name = f"{k}(mA)"df1 = power_df[power_df[name] > v]if k == "threadList":name = "thread_num"df1 = thread_df[thread_df[name] > v]if f'{k}(KB)' in traffic:name = f'{k}(KB)'df1 = traffic_df[traffic_df[name] > v]cases_df = pd.concat([df1, cases_df]).sort_values("datetime", ascending=True)error_index = list(cases_df[cases_df[name] > 0].index)for i in error_index:cases_df.loc[i, 'desc'] += f"{k}超过阈值;"try:cases_df.loc[i - 1, 'desc'] += f"{k}超过阈值;"except Exception:passtry:cases_df.loc[i + 1, 'desc'] += f"{k}超过阈值;"except Exception:passcases_df = cases_df[pd.notnull(cases_df['fullName'])]cases_df = cases_df[cases_df['flag'] == True]new_df = pd.DataFrame(cases_df, columns=base_title)return new_df.to_dict("records")
测试
cases_data = d.add_desc(device_cpu_rate=700, user=125, system=300, idle=700, pid_cpu=300,free_ram=2575, pid_pss=424, total_ram=5478,tempreture=36, voltage=4,threadList=255,device_transport=5782, device_receive=155658, device_total=161440, pid_tx=5782, pid_total=161450, pid_rx=155667,)
[
...
{'datetime': Timestamp('2022-08-01 14:05:17'), 'flag': True, 'fullName': 'src.cases_android.wy.test_health.TestMedicationReminder#test_edit_medication_reminder', 'status': 'passed', 'labels': '微医APP_健康_用药提醒-修改用药提醒时间(@钟鑫)', 'start': 1659333917269.0, 'stop': 1659333926307.0, 'duration': 9038.0, 'parameters': nan, 'statusDetails': "{'message': '', 'trace': ''}", 'kano_url': nan, 'steps': '1-点击一条用药提醒记录;1.1-点击「用药提醒_其中一条用药提醒」;2-选择必要时用药;2.1-获取元素的坐标;2.2-点击坐标「558.0」「640.5」所在的位置;2.3-点击坐标「558.0」「640.5」所在的位置;2.4-点击坐标「558.0」「640.5」所在的位置;2.5-从元素「用药提醒_用药时间-每隔几天用药」滑动到元素「用药提醒_用药时间-每隔几小时用药」的位置;2.6-点击「通用_完成」;3-点击保存;3.1-点击「通用_保存」;4-查看提醒时间为必要时;4.1-转换参数化元素;4.2-查看「用药提醒_用药时间」是否存在', 'desc': ';system超过阈值;device_cpu_rate超过阈值;voltage超过阈值;voltage超过阈值;voltage超过阈值;'}
...
]
最后: 可以在公众号:伤心的辣条 ! 自行领取一份216页软件测试工程师面试宝典文档资料【免费的】。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。
现在我邀请你进入我们的软件测试学习交流群:【746506216
】,备注“入群”, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路。
喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一 键三连哦!
软件测试工程师自学教程:
这才是2022最精细的自动化测试自学教程,我把它刷了无数遍才上岸字节跳动,做到涨薪20K【值得自学软件测试的人刷】
接口性能测试 — 软件测试人必会618实战场景分析
软件测试工程师月薪2W以上薪资必学技能 — Python接口自动化框架封装.
美团面试真题_高级测试25K岗位面试 — 软件测试人都应该看看
测试开发之全面剖析自动化测试平台 — 软件测试人的必经之路
软件测试必会_Jmeter大厂实战 — 仅6步可实现接口自动化测试
Jmeter实战讲解案例 — 软件测试人必会
UI自动化测试框架搭建-标记性能较差用例相关推荐
- UI自动化测试框架搭建——标记性能较差用例
在拿到性能数据后需要将数据利用起来,下面对性能数据进行分析 实现:如果性能达到设定的阈值,那么这段时间执行的用例就是性能较差的用例 确定阈值 首先确定一个阈值来当做性能的告警值,暂定为以下算法 # t ...
- 20.UI自动化测试框架搭建-标记性能较差用例
在拿到性能数据后需要将数据利用起来,下面对性能数据进行分析 实现:如果性能达到设定的阈值,那么这段时间执行的用例就是性能较差的用例 确定阈值 首先确定一个阈值来当做性能的告警值,暂定为以下算法 # t ...
- WEB UI自动化测试框架搭建(一)_公用方法Utils
本栏目内的所有项目使用的都是PyCharm 2020.1专业版,可以下载后自行在网上找教程破解. WEB UI自动化测试框架搭建(一)~(七)源代码:https://download.csdn.net ...
- python ui自动化测试框架_基于python语言下的UI自动化测试框架搭建(一)
最近在搭一个UI自动化测试框架,想把整个搭建过程分享出来,如果有不对的地方,希望大家能够指正,首先创建一个名称为,antomation_framework_demo的工程文件, pycharm中工程及 ...
- 基于python语言下的UI自动化测试框架搭建(四)
testsuits:案例执行 创建baidu_search1.py文件,这里会展示两种执行方式,一种是直接调用base_page中封装好的常用操作方法,另外一种是先调用baidu_homepage.p ...
- ui自动化测试框架_数据驱动 vs 关键字驱动:对搭建UI自动化测试框架的探索
谢谢打开这篇文章的每个你 关注我们 点击右上角 ··· 设为星标 UI自动化测试用例剖析 让我们先从分析一端自动化测试案例的代码开始我们的旅程.以下是我之前写的一个自动化测试的小Demo.这个Demo ...
- 实战 | UI 自动化测试框架设计与 PageObject 改造
本文节选自霍格沃兹<测试开发实战进阶>课程教学内容,进阶学习文末加群. 在 UI 自动化测试过程中,面对复杂的业务场景,经常会遇到这样的挑战: 简单的录制/回放速度快,但无法适应复杂场景: ...
- APP自动化测试框架搭建(六)--uiautomator2、web-editor基础操作
第一章 APP自动化环境搭建(Mac版) 第二章 APP自动化环境搭建(Windows版) 第三章 adb命令 第四章 元素定位.元素操作 第五章 APP自动化测试框架搭建 Python+Appium ...
- API接口自动化测试框架搭建(一)-总体需求
(一)-总体需求 1 实现目的 2 功能需求 3 其他要求 4 适用人员 5 学习周期 6 学习建议 7 内容直达 8 反馈联系 1 实现目的 API接口自动化测试,主要针对http接口协议: 便于回 ...
最新文章
- html绘制圆形和弧形的代码,通过HTML5 Canvas API绘制弧线和圆形的教程
- 4.方向-世界坐标系
- python paramiko使用_python paramiko 模块使用方法
- Java中Integer类型的整数值的大小比较
- SQL Server高级查询之常见数据库对象(触发器)第五章节
- 最速下降法python_算法最优化之最速下降法
- u-boot源码个别分析
- 以退为进还是被逼无奈?创始人王劲离职后,景驰科技该何去何从?
- - 模块“VPMC“启动失败,未能启动虚拟机?
- Web——HTML常见标签及用法
- 【PTA】匿名内部类:实现Comparator比较器
- js【详解】arr.splice() 数组拼接
- Ubuntu 软件仓库源
- 业务流程编排设计和实现
- OpenCV—Python 对比度与亮度调整
- 兴趣探测的模型化探索
- Mysql大表数据清理方案
- 中国物流园区潜力评估及十四五战略研究报告2022-2028年
- Agile 是什么?
- 与高手连接有哪些常用的方法?
热门文章
- ELK学习之入门搭建使用
- oracle 怎么注释代码,oracle代码段注释符号是什么
- python命名标识符_详解Python标识符命名规范
- 名人投资加密货币:推动行业发展的重要力量(连载一)
- 芯片内部存储器介绍(转载)
- 矩阵分解模型——SVD与SVD++
- 《阿里云服务器搭建》------ 安装Jenkins
- android 微信朋友圈时间不对,微信怎么重新编辑朋友圈 注意是有时间限制的
- 获取两个日期之间日期列表
- Visual Studio VS工程文件作用的.sdf(.db)和ipch文件夹的处理