Android App的性能测试是移动测试过程中必不可少的一个环节。在我们项目组内,性能测试的过程是这样的,先设置测试场景,然后一边手工执行场景,一边通过工具获取性能数据,为了减少误差,一个场景一般重复执行3-5次,测试完后将各种性能数据整理成报告。这个过程如果是一个经验丰富的测试工程师去做,可能要花半天到时间,而如果是一个新人去做,甚至可能要花两天时间。而且有时候还会遇到,刚测完,开发说优化了性能,又需要重新测试。这还只是一个Android端的时间,如果再加上iOS端,时间加倍。对于这样一个现状,我们急需探索出一种自动化的方式提高性能测试的效率。本文接下来将要介绍云测试平台在自动化性能测试方面的探索和成果。
  需求分析
  作为一个负责任的测试开发工程师,我们首先要搞清楚需求,即产品线的性能测试到底要怎么测,要测哪些数据。于是,我跟着参与了产品线的性能测试方案及标准的讨论。了解到的性能测试需要采集的数据有:1.响应时间;2.耗电量;3.CPU,内存消耗,网络流量;4.渲染帧率。而这几组数据需要覆盖的测试场景大概有16种,如下表所示。

  方案调研
  UI自动化与性能测试相结合
  在Android端,获取性能数据的方式有很多种,可以通过开源工具采集,可以通过adb命令获取,也可以调用系统API获取。各种方法采集的数据基本差别不大,重点是场景操作和数据整理比较麻烦。既然要提高测试效率,那好的方式肯定是通过自动化来解决。自动化的框架有很多种,这里不一一做讨论了,我们采用的是Appium框架,但是做了二次封装和改进,易用性更好。关于云测试平台UI自动化功能的使用方法介绍,大家可以参考云测试平台帮助文档一文。
  测试方案
  对于CPU,内存,FPS,流量这几组数据,云测平台早可以提供测试了。通过一个与UI自动化并行的线程来发送adb命令获取应用的性能数据。我们需要解决的是如何设置性能测试的起点和终点,还有一个场景多次重复测试的问题。
  那么我们需要想办法测试响应时间,我们采用的方案是设置一个待加载页面的基准控件,利用Appium的元素查找功能一直循环查找,一旦控件找到了,则认为页面加载成功,这中间的时间差即为页面响应时间。这个时间虽然没有代码插桩准确,但误差范围基本控制在100ms内,对整体测试结果的影响不大。
  方案实施
  开启一个性能测试的线程
  关于获取方式前面也介绍了,话不多说,直接上代码:
@Override
public void run() {
// TODO Auto-generated method stub
this.running = true;
while (running) {
String time = String.valueOf(System.currentTimeMillis());
time = CalendarDate.GetCurrentTime();
//获取内存数据
int [] memArray = AndroidPerformanceTools.getMemoryInfo(androidPerformance.getPkgname(), androidPerformance.getDevice());
int totalMem = memArray[0];
int appMem = memArray[1];
//获取CPU数据
int cpuUsage = AndroidPerformanceTools.getCPUInfo(androidPerformance.getPkgname(), androidPerformance.getDevice());
//获取FPS
float fps = AndroidPerformanceTools.getFPSInfo(androidPerformance.getPkgname(), androidPerformance.getDevice());
//获取流量数据
long [] trafficArray = AndroidPerformanceTools.getTrafficInfo(androidPerformance.getPkgname(), androidPerformance.getDevice());
long totalTrffic = trafficArray[0];
long recTraffic = trafficArray[1];
long sndTraffic = trafficArray[2];
//数据初始化
if (this.androidPerformance.getAndroidPerformanceData().getInittotal() == -1
&& totalTrffic > 0) {
this.androidPerformance.getAndroidPerformanceData().setInittotal(totalTrffic);
this.androidPerformance.getAndroidPerformanceData().setInitrec(recTraffic);
this.androidPerformance.getAndroidPerformanceData().setInitsnd(sndTraffic);
}
//汇总数据
MemInfo memInfo = new MemInfo(time, totalMem, appMem);
FPSInfo fpsInfo = new FPSInfo(time, fps);
CPUInfo cpuInfo = new CPUInfo(time, cpuUsage);
TrafficInfo trafficInfo = new TrafficInfo(time, totalTrffic, recTraffic, sndTraffic);
this.androidPerformance.getAndroidPerformanceData().getCpuinfolist().add(cpuInfo);
this.androidPerformance.getAndroidPerformanceData().getMeminfolist().add(memInfo);
this.androidPerformance.getAndroidPerformanceData().getTraffinfolist().add(trafficInfo);
this.androidPerformance.getAndroidPerformanceData().getFpsinfolist().add(fpsInfo);
//设置采集间隔时间
try {
Thread.sleep(this.sleepTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
  设置开始和结束的点
  由于UI自动化的执行每次都是从启动App开始,但性能数据的收集却是针对具体某个场景的,比如进入生活缴费页面。因此为了方便设置性能测试的开始和结束时间,我们在UI自动化脚本的录制action中加了两个字段:startPerformance和stopPerformance。用户可以在脚本的任意位置加入这两个action,但主要先后关系,而且需要配对使用。当我们在执行脚本的时候,遇到startPeformance,启动性能测试线程,然后遇到stopPerformance,则停止线程,并保存数据。一个完整的用于做性能测试的脚本如下所示:

  脚本