一、移动端性能测试指标
性能测试需要收集的指标项包含:页面时长、电量、CPU、内存、流量、包大小。
目前阶段主要关注的指标项:页面时长、电量
二、指标收集&分析方法
- 页面时长:RD跟进所需场景进行埋点并上报Omega进行场景化、链路化统计分析
- 电量:Android使用batterystatus进行电量收集、使用Battery Historian进行电量数据分析;iOS diagnostics 方案可行性待定
三、电量测试方法
step1:打开App执行性能场景
step2:性能场景执行完毕后,通过adb batterystats 命令获取电量日志
step3:导出电量报告bugreport,借助Battery Historian 进行可视化分析
Battery Historian工具介绍: https://github.com/google/battery-historian
四、电量度量标准
五、性能测试场景
六、测试前提
在测试之前,确保以下测试环境要素都已满足(适用Android/iOS):
七、测试机型
八、测试版本
九、QA人员
十、性能测试报告
如何获取手机性能测试数据FPS
本人在做APP性能测试的过程中,为了测试APP在各个场景下的流畅度,需要收集手在各个运行场景下的fps数据,经常查资料,使用的是adb shell命令:
adb shell dumpsys gfxinfo 包名
分享代码,供大家参考。
测试方法:
1 Fps fps = new Fps();
2 fps.start();
3 //do something
4 fps.stopFps();
5 fps.join();
多线程类的代码:
1package monkeytest;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.util.ArrayList;
8import java.util.List;
9import java.util.Random;
10import java.util.regex.Matcher;
11import java.util.regex.Pattern;
12import source.AppLocalMySql;
13import source.Common;
14
15public class Fps extends Thread {
16 private boolean KEY = true;
17 private static String testName = "normal";
18 private int mark = Common.mark;
19
20 @Override
21 public void run() {
22 while (KEY) {
23 execCmdAdb("adb shell dumpsys gfxinfo com.happyjuzi.apps.juzi");
24 Common.getInstance().sleep(5000);
25 }
26 }
27
28 public int getMatcher(String text, Pattern pattern) {
29 Pattern newattern = Pattern.compile(pattern.toString().trim());
30 Matcher matcher = newattern.matcher(text);
31 List<String> numbers = new ArrayList<>();
32 while (matcher.find()) {
33 String number = matcher.group(0);
34 numbers.add(number);
35 }
36 double result = 0;
37 for (int i = 0; i < numbers.size(); i++) {
38 double num = Common.getInstance().changeStringToDouble(numbers.get(i));
39 result += num;
40 }
41 int total = (int) result + new Random().nextInt(2);
42 return total;
43 }
44
45 /**
46 * 结束线程
47 */
48 public void stopFps() {
49 this.KEY = false;
50 }
51
52 /**
53 * 执行cmd命令
54 *
55 * @param cmd
56 * 命令
57 */
58 public void execCmdAdb(String cmd) {
59 Pattern pattern = Pattern.compile(" ([0-9]{1,2}+\\.[0-9]{2})");
60 output("正在执行:" + cmd);
61 String OSname = System.getProperty("os.name");
62 try {
63 Process p = null;
64 if (OSname.contains("Mac")) {
65 p = Runtime.getRuntime().exec(Common.ADB_PATH + cmd);
66 } else {
67 p = Runtime.getRuntime().exec("cmd /c " + cmd);
68 }
69 // 正确输出流
70 InputStream input = p.getInputStream();// 创建并实例化输入字节流
71 BufferedReader reader = new BufferedReader(new InputStreamReader(input));// 先通过inputstreamreader进行流转化,在实例化bufferedreader,接收内容
72 String line = "";
73 while ((line = reader.readLine()) != null) {// 循环读取
74 if (line.startsWith(" ")) {
75 Matcher matcher = pattern.matcher(line);
76 if (matcher.find()) {
77 AppLocalMySql.getInstance().saveFps(testName, mark);
78 getMatcher(line, pattern);// 输出
79 }
80 }
81 }
82 reader.close();// 此处reader依赖于input,应先关闭
83 input.close();
84 // 错误输出流
85 InputStream errorInput = p.getErrorStream();// 创建并实例化输入字节流
86 BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorInput));// 先通过inputstreamreader进行流转化,在实例化bufferedreader,接收内容
87 String eline = "";
88 while ((eline = errorReader.readLine()) != null) {// 循环读取
89 System.out.println(eline);// 输出
90 Common.getInstance().saveToFile(eline, "runlog.log");// 保存,false表示不覆盖
91 }
92 errorReader.close();// 此处有依赖关系,先关闭errorReader
93 errorInput.close();
94 } catch (IOException e) {
95 output("执行" + cmd + "失败!");
96 e.printStackTrace();
97 }
98 }
99
100 public void output(String text) {
101 System.out.println(text);
102 }
103
104 public void output(Object... object) {
105 if (object.length == 1) {
106 output(object[0].toString());
107 return;
108 }
109 for (int i = 0; i < object.length; i++) {
110 System.out.println("第" + (i + 1) + "个:" + object[i]);
111 }
112 }
113}
往期文章精选
来源公众号: