9.2专项测试-Android性能测试黑盒分析-1

## 1. 专项测试 * 业务测试:面向新需求 * 回归测试:面向已交付需求 * 专项测试:面向非功能需求的各类质量唯独特征
表现用户维度技术维度
崩溃crash,弱网检测崩溃
1.某个页面,因为研发处理不合适,点击页面的某个控件、页面加载中接口报错(如返回null值,或空列表)、前端的列表计算有问题(数组越界)、内存问题引发崩溃,一般使用自动遍历、monkey测试频繁的去检测app的健壮性,模拟大量的随机事件。新业务中一般使用断点模拟接口异常,使用自动遍历、monkey测试不一定能有效模拟这种场景
2.还有一些特殊行为也会触发,比如横竖屏切换
3.进入一个app,快进快退,也会引发崩溃。
卡顿掉帧、gc、CPU卡顿测试:需要借助与安卓官方提供的技术手段,进行相关的数据分析。原因:CPU使用、GPU渲染,gc,内存泄漏
内存泄漏测试
method profile
响应慢启动时间、交互响应、H5加载响应时间:分为冷启动与热启动
交互响应:界面切换分析起接口调用时间和处理过程
H5性能测试:严格分析出来资源的消耗情况
发热、掉电快CPU、MEM、IO、network、GPS等硬件使用method profile(了解CPU的使用情况)、gc统计、IO使用、流量消耗、硬件(屏幕等)使用统计、耗电量统计
兼容性问题机型覆盖、回归兼容性测试、自动化测试、自动遍历、monkey测试
主要与机型有关,手机品牌日益聚焦,目前覆盖TOP100就够了。

2. 常用的解决方案:

  • ddms
    * 谷歌开发的安卓分析工具套件,不过逐渐废弃了。
  • Android studio最新版本的集成工具
    * 关于性能的分析,正在逐渐有独立的工具编程IDE自身的集成。
  • 代码插桩
    * 可以帮我们发现很多的问题,比如内存的泄漏,对CPU的使用,当前CPU与内存的占用情况,在代码层也可以分析出来。在应用中嵌入一些代码统计指标也可以分析。有些大厂自带了性能监控的SDK,不断统计手机的网络消耗、CPU与内存消耗,上传到服务端进行综合的分析,判断用户有没有出现崩溃、内存不足等手机各方面的数据。

3. 崩溃问题检测

3.1 典型问题:

  • ANR
    假设主线程发起一次网络请求,这次网络请求5秒内没有得到响应,被系统检测到,系统就会弹窗提示ANR。ANR在6.0之前非常多,现在很少了。原因是在开发app的时候,如果在原声页面发起一次网络请求,对于Android Studio来说在编译时就编译不过,会告知这块代码有风险,必须要改,否则编译不过。

  • Force Close
    假设页面有一个列表,在处理列表是,出现数组越界,系统弹窗提示Force Close

  • 原生的Crash
    用C语言或其他语言在底层封装了一些库,结果这个库崩了,而异常未捕捉,也会崩溃

3.2 基本测试方法

  • 发布前
    * monkey测试+AppCrawler自动遍历:遍历所有的界面,创造一些随机时间,来去模拟能不能触发系统各种诡异的bug
    * 结合各类场景用例
  • 发布后
    * 埋点 在主线程,注册一个异常处理逻辑就可以了
    * 接入外部SDK buglly本质在app内注册一个线程的异常处理机制,一旦线程崩溃,他会首先捕获这个异常,把这个异常统计分析,发送到云端

3.3 常见场景

3.3.1 接口返回异常(一般通过Charles或mock来实现)

  • 弱网
    * 完全超时
    * 2G 3G
    * 场景:设定一个弱网的情况如2G,或者让响应时间超过3秒钟。进入app,立即退出(可以通过自动化去模拟),此时观察系统有没有出现问题。进入app的时候,应用会发起一个网络请求到服务器。用户发现页面反应比较慢,返回,此时发起网络请求的异步线程还在请求,退出时并未取消请求。请求完成后,就回去渲染当时的页面,如果开发的代码有问题,在异步线程里去渲染一个已经退出的页面即空对象,就会出现空指针。
  • null返回:后台的某些接口出现Null或空列表的返回,应用也要能够处理
  • 字段类型变更:某些开发随意修改返回值类型,造成客户端崩溃。

3.3.2 逻辑问题:

  • 打开新页面再快速返回,异步线程问题
  • 横竖屏切换、前后台切换

3.4 崩溃分析

4. 交互体验

4.1 原生页面响应时间

  • app交互
    * 冷启动、热启动
    * 事件响应、内部加载速度
  • 接口性能
  • h5加载

4.1.1 冷启动—adb

  • 传统的方式,基本已废弃 没有其他相关技术,可以使用传统方式简单统计各个Activity的响应时间,但其时间是不准的。
  • 埋点 更多时候是采用埋点,一般一个app会在应用的各个界面进行埋点。比如Activity加载需要多久,这中间又有好几个处理过程,比如去访问服务端获取数据,客户端在获取到数据后再进行渲染。在不同的阶段里面创建自己的埋点,借助埋点去统计各个过程的耗时,这种统计才是准确的。

下面2种统计方式都只统计了Activity的展现时间,里面的数据并未完全加载完。如果想统计数据完全的被加载,还需要另外的统计方法。虽然这2种方法不是特别准确,还是能发现不少问题。

adb shell am force-stop com.UCMobile
adb shell am start -S -W com.UCMobile/com.uc.browser.InnerUCMobile
#ThisTime:最后一个启动的Activity的启动耗时;
#TotalTime:自己的所有Activity的启动耗时;
#WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)
参考:https://blog.csdn.net/yan_startwith2015/article/details/77991571 ```#shell adb shell am force-stop com.UCMobile adb logcat |grep ActivityManager.*Displayed ```

4.1.2 冷启动—埋点

为了更准确统计启动时间,一般采用埋点。app会在各个界面进行埋点,Activity加载需要多久,中间还有好几个处理过程,比如访问后端去请求数据再进行渲染,根据埋点统计各个过程。

埋点有2种方式:研发团队埋点、通用的SDK埋点
应用启动(Application onCreate)后,进入主线程(Main Thread),在主线程中初始化Activity(Activity init),创建Activity(Activity onCreate),之后加载事件、渲染布局、展示,此时页面能够展示。除此之外还有异步加载。DisplayedTime和reportFullyDrawn是比较关注的。相比于adb统计,埋点统计更精准。

主要的流程:

  • Application OnCreate
    * 加载第三方的sdk
  • ActivityOnCreate
    * 加载自身的逻辑
    * 发送请求获取数据 json
    * 渲染界面 List

使用第三方sdk:

<!--1.集成SDK,在Module的build.gradle文件中添加依赖和属性配置-->
dependencies {
    compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.2.0
}
<!-- 2.初始化,获取APP ID并将以下代码复制到项目Application类onCreate()中,Bugly会为自动检测环境并完成配置-->
CrashReport.initCrashReport(getApplicationContext(), "注册时申请的APPID", false); 

有很多的sdk和系统的默认设置都会加到Application类或Activity类的onCreate()中,如第三方消息推送,这就导致onCreate()的逻辑较多,进而影响应用的启动、界面的加载都会有不同程度的影响,因此启动事件需要使用合适的方法进行度量。

4.1.3 代理工具:Activity启动事件+接口响应时间(第一个接口的发起时间和最后一个接口的响应完成时间)

  • 1.使用adb查看Activity的启动事件
  • 2.借助于Charles等抓包工具可以获取接口耗时 使用代理工具抓包,分析界面到底有多少个网络请求,每个网络请求的耗时

4.2 H5页面

可以使用chrome://inspect查看设备上H5页面的响应。
chrome部分版本取消了一个css标签的支持,导致页面混乱,此时可以下载版本62的chrome

1.根据版本号获取id https://omahaproxy.appspot.com/ 如62.0.3202.62的id为499098
2.替换id去下载chrome https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/499098/

4.2.1 以浏览器模拟手机,页面如下


每个字段具体意义https://developers.google.com/devtools/docs/network#resource-network-timing
Request Table默认显示以下类目:

  • Name 资源的名称
  • Status HTTP状态码
  • Type 已请求资源的MIME类型
  • Initiator 发起请求的对象或进程。值为以下选项之一
    * Parser Chrome的HTML解析器发起请求
    * Redirect HTTP重定向发起请求
    * Script 脚本发起请求
    * Other 某些其他进程或操作发起请求,例如用户通过连接或者在地址栏输入网址导航到页面
  • Size 响应标头(通常为数百字节)加响应正文(有服务器提供)的组合大小
  • Time 从请求开始至响应中接收到最终字节的总持续时间
  • Timeline 可以显示所有网络请求的可视瀑布。点击此列的标题可以显示一个包含更多字段的菜单。

4.2.2查看DOMContentLoaded和load事件信息


Network面板突出显示两种事件:DOMContentLoaded和load。

解析页面的初始标记时会触发DOMContentLoaded。此事件将在Network面板的两个地方显示

  1. Overview窗格中的蓝色竖线表示事件
  2. 在Summary窗格中,可以看到时间的确切时间
页面完全加载时将触发load。此事件显示在三个地方 1. Overview窗格中的红色竖线 2. Requests Table中的红色竖线也表示事件 3. 在Summary窗格中,可以看到事件的确切时间

ResourceTiming API提供了接受各个资源事件的有关的大量详细信息。

4.2.3 请求生命周期的主要阶段包括:

  • 重定向
    * 立即开始 startTime
    * 如果正在发生重定向,redirectStart也会开始
    * 如果重定向在本阶段未发生,将采集redirectEnd
  • 应用缓存
    * 如果应用缓存在实现请求,将采集fetchStart时间
  • DNS
  • TCP
    * connectStart 在初始连接到服务器时采集
    * 如果正在使用TLS或SSL,secureConnectionStart将在握手(确保连接安全)开始时开始
    * connectEnd将在服务器的连接完成时采集
  • 请求
    * requestStart 会在某个资源的请求被发送到服务器后立即采集
  • 响应
    * responseStart 是服务器初始响应请求的时间
    * responseEnd 是请求结束并且数据完成检索的时间

如果有重定向,就进行重定向;如果没有重定向,就判断本地有没有cache。如果资源没有访问过,就查DNS,找网站。找到网站,与具体的网站建立连接,连接完成后,发起请求,服务端进行响应。此时界面仍然是空白的,直到DOMContentLoaded事件,load事件表明页面加载完成

4.2.4 Devtools中查看指定条目完整的耗时信息

  • Queuing 如果某个请求正在排队,则指示:
    * 请求已被选人引擎推迟,因为该请求的优先级被视为低于关键资源(例如脚本/样式)的优先级。图像经常大声这种情况。
    * 请求已被暂停,以等待将要释放的不可用TCP套接字
    * 请求已被暂停,因为在HTTP 1.0上,浏览器仅允许每个源拥有6个TCP连接
    * 生成磁盘缓存条目所用的时间(通常非常迅速)
  • Stalled/Blocking 请求等待发送所用的时间。可以是等待Queuing中介绍的任何一个原因。此外,此时间包含代理协商所用的任何时间
  • Proxy Negotiation 与代理服务器连接协商所用的时间。
  • DNS Lookup 执行DNS查询所用的时间。页面上的每一个新域都需要完整的往返才能进行DNS查询。
  • Initial Connection/Connecting 建立连接所用的时间,包括TCP握手/重试和协商SSL的时间
  • SSL 完成SSL握手所用的时间
  • Request Sent/Sending 发出网络请求所用的时间。通常不到1毫秒
  • Waiting(TTFB 等待初始响应所用的时间,也称为第一字节的时间。此时间将捕捉到服务器往返的延迟时间,以及等待服务器传送响应所用的时间。谷歌建议至少在200毫秒以下
  • Content Download/Downloading 接收响应数据所用的时间

4.2.5 webview开关

模拟器默认支持
针剂需要打开app内开关

//启用WebView调试,需要在WebView类上调用静态方法setWebContentsDebuggingEnabled
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
    WebView.setWebContentsDebuggingEnabled(true);
}
posted on 2018-11-11 09:43  singleSpace  阅读(531)  评论(0编辑  收藏  举报