Android APP使用Python进行性能测试以及测试框架
- 启动APP命令
adb shell am start -W -n package/activity- 停止App命令
adb shell am force-stop package获取某个APP的packageName和ActivityName的命令
adb logcat | grep START然后打开你想获取packageName和ActivityName的应用即可。
启动APP命令和冷启动一样
停止App命令
# 模拟点击back键 adb shell input keyevent 3
两种方案:
获取命令执行时间,作为启动时间参考值
classApp(object): def__init__(self): self.content=""self.startTime=0# 启动APPdeflaunch_app(self): cmd='adb shell am start -W -n org.chromium.webview_shell/.WebViewBrowserActivity'# type: strself.content=os.popen(cmd) # 停止app@staticmethoddefstop_app(): # 冷启动停止的命令# cmd = 'adb shell am force-stop org.chromium.webview_shell'# 热启动停止的命令cmd='adb shell input keyevent 3'os.popen(cmd) # 获取启动时间defget_launched_time(self): forlineinself.content.readlines(): if"ThisTime"inline: self.startTime=line.split(":")[1] breakreturnself.startTime# 单次测试过程deftest_process(self): self.app.launch_app() time.sleep(5) elapsed_time=self.app.get_launched_time() self.app.stop_app() time.sleep(3) current_time=self.get_current_time() self.all_data.append((current_time, elapsed_time)) # 多次执行测试过程defrun(self): whileself.counter>0: self.test_process() self.counter=self.counter-1
在命令前后加上时间戳,以差值作为参考值
# 单次测试过程deftest_process(self): time_before_launch=int(time.time()) self.app.launch_app() time_after_launch=int(time.time()) time.sleep(5) # elapsed_time = self.app.get_launched_time()elapsed_time=time_after_launch-time_before_launchself.app.stop_app() time.sleep(3) current_time=self.get_current_time() self.all_data.append((current_time, str(elapsed_time))) # 多次执行测试过程defrun(self): whileself.counter>0: self.test_process() self.counter=self.counter-1
可以多次计算启动时间值,并保存到本地csv文件,进行统计分析,求平均值等,第一次获得的值最好弃用。
# windows系统的cmd中,用findstr来过滤字符,不能用grep。 adb shell dumpsys cpuinfo | grep packagename# 单次测试过程deftest_process(self): # window 下用findstr,Mac下用grepcmd="adb shell dumpsys cpuinfo | findstr org.chromium.webview_shell"self.result=os.popen(cmd) cpu_value=0forlineinself.result.readlines(): cpu_value=line.split("%")[0] current_time=self.get_current_time() self.all_data.append((current_time, cpu_value))获取进程ID指令
# windows下用findstr代替grep,否则拿不到结果 adb shell ps | grep packagename
获取进程ID的流量指令
# pid就是上面指令获取的进程ID adb shell cat /proc/pid/net/dev
# 单次测试过程deftest_process(self): # 执行获取进程ID的指令 window 下用findstr,Mac下用grepcmd="adb shell ps | findstr org.chromium.webview_shell"result=os.popen(cmd) # 获取进程IDpid=result.readlines()[0].split(" ")[5] # 获取进程ID使用的流量traffic=os.popen("adb shell cat /proc/"+pid+"/net/dev") forlineintraffic: # 第一个网卡的数据if"eth0"inline: # 将所有空行换成#line="#".join(line.split()) # 然后按#号进行拆分,获取到收到和发出的流量值receive=line.split("#")[1] transmit=line.split("#")[9] # 第二个网卡的数据elif"eth1"inline: line2="#".join(line.split()) # 然后按#号进行拆分,获取到收到和发出的流量值receive2=line2.split("#")[1] transmit2=line2.split("#")[9] # 计算所有流量之和all_traffic=string.atoi(receive) +string.atoi(transmit) +string.atoi(receive2) +string.atoi(transmit2) # 按KB计算流量值all_traffic=all_traffic/1024# 获取当前时间current_time=self.get_current_time() # 将获取到的数据存到数组中self.all_data.append((current_time, all_traffic))运行后的结果:
timestamp,traffic 2020-03-13 11:35:36,136535 2020-03-13 11:35:41,136791 2020-03-13 11:35:47,166458 2020-03-13 11:35:52,264812 2020-03-13 11:35:57,380940 用最后一条流量值减去第一条流量值,得到本次测试运行时消耗掉的流量,然后和以往版本以及竞品进行对比,然后发现流量消耗的问题。
adb shell dumpsys battery但是手机连接USB之后,会进入充电状态,测试电量需要在非充电的情况下,所以可以使用下面的命令切换充电状态
# 切换到非充电状态,status = 2 代表充电,非2就是非充电 adb shell dumpsys battery set status 1# 单次测试过程deftest_process(self): cmd="adb shell dumpsys battery"result=os.popen(cmd) forlineinresult: if"level"inline: power=line.split(":")[1] # 获取当前时间current_time=self.get_current_time() # 将获取到的数据存到数组中self.all_data.append((current_time, power)) # 多次执行测试过程defrun(self): cmd="adb shell dumpsys battery set status 1"os.popen(cmd) whileself.counter>0: self.test_process() self.counter=self.counter-1# 每5秒采集一次数据, 真实测试场景建议在0.5-1小时time.sleep(5)adb shell top # -d 刷新频率, 1 代表多久刷新一次,单位秒 adb shell top -d 1 # 输出到指定文件,测试完终止命令就可以分析指定文件 adb shell top -d 1 > meminfo # 筛选指定包名,进行分析, windows上可以用type代替cat, findstr代替grep cat meminfo | grep packagenameVSS - Virtual Set Size 虚拟消耗内存
RSS - Resident Set Size 实际使用物理内存
脚本负责对命令行中测试后生成的meminfo文件进行分析,然后生成分析数据到csv文件,然后可以利用该csv文件进行图表绘制,内存数据获取时,建议测试时间长一点,方便分析使用过程中内存数据是否稳定,vss和rss分别分析。
# 控制类classController(object): def__init__(self): # 定义收集数据的数组self.all_data= [("id", "vss", "rss")] # 分析数据defanalyze_data(self): content=self.read_file() i=0forlineincontent: if"org.chromium.webview_shell"inline: printlineline="#".join(line.split()) # 角标7和8不是固定的,要看你生成的meminfo文件里vss和rss出现的位置来确定vss=line.split("#")[7].strip("K") rss=line.split("#")[8].strip("K") # 将获取到的数据存到数组中self.all_data.append((i, vss, rss)) i=i+1# 读取数据文件@staticmethoddefread_file(): mem_info=file("meminfo", "r") content=mem_info.readlines() mem_info.close() returncontent# 数据的存储defsave_data_to_csv(self): csv_file=file('meminfo.csv', 'wb') writer=csv.writer(csv_file) writer.writerows(self.all_data) csv_file.close() if__name__=='__main__': controller=Controller() controller.analyze_data() controller.save_data_to_csv()frames per second - 每秒的帧数
Android中每一帧的绘制时间大于16秒,则可能会产生卡顿的现象,可以借助设置-开发者选项-GPU呈现模式分析,选择在屏幕上呈现为条形图,屏幕中横着的绿线就是16ms的基准线,高于绿线的条形图就是发生卡顿的帧
描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次
可以借助设置-开发者选项-调试GPU过度绘制-选择显示过度绘制区域,从最优到最差:蓝,绿,淡红,红。