写点什么

APP 专项测试实战

用户头像
刘帅强
关注
发布于: 2021 年 08 月 27 日

APP 专项测试

Web 性能

WebView 性能

network

  • 在弱网测试时需要清除缓存

  • waterfall

  • 蓝线 dom 加载

  • 红线 所有元素加载

  • Capture screenshots: 捕获一个截图 简单的分析

  • 底部总结性性展示

  • 过滤表达式

  • doman . 展示 domain 中的资源, *.com

  • has- response-header . 包含指定的 HTTP 响应 header

  • is . 表达式

  • larger-than. 展示大于某个尺寸的资源, 1000 等于 1k

  • methods 指定 http 请求方法,比如 get 或者 post

  • 过滤表达式 2

  • mine-type 资源 mine 类型,比如 application/json

  • scheme.HTTP (scheme:http)或者 HTTPS(scheme:https)

  • status-code: 状态码

  • 资源过滤

  • 大于 10k 的图片资源

  • mime-type:image/png larger-than:1k

  • 所有状态码为 304 的请求

  • schema:https status-code:304

  • 域名以.com 结尾,使用 http 协议

  • domain:*.com scheme:https

performance

  • 火焰图

  • 调用关系

  • 页面加载有几个步骤

  • HTML 渲染成 dom 渲染过程中遇到了 JS 会先加载 js


<html lang = 'en'><head> <menta charset = "UTF-8"> <title> Title</title></head>  <script>var sleep = function(time)    {var startTime = new Date().getTime() + parseInt(time, 10);     while(new Date().getTime()< startTime){}}    while (new Date().getTime()<startTime){}};</script><body onunload = "sleep(3000)"></body>  </html>
复制代码

前端加载情况分析

https://www.w3.org/TR/navigation-timing/


unload


处于同源时,进行时间计算

protocol, port 和 host 相同


app 性能

android 真机不能切换进 webview 模拟器之所以能切换进 webview 是因为使用了 android 6.0 的 bug

  1. 找到一个 webView 页面

  2. 切进来用 js 获取 w3c 提供的 timing

  3. 使用 python 进行一次计算

caps ={}caps["platformName"]="Android"caps["deviceName"] = "127.0.0.1:7555"caps["appPackage"]="com.xueqiu.android"caps["appActivity"]=".view.WelcomeActivityAlias"caps["noReset"]="true"caps['chromedriverExcutable']="chromedriver2.2.exe"#caps["skipSerInstallation"]= True#caps["skipDeviceInitialization"] =Truedriver= webdriver.Remote("http://localhost:4723/wd/hub",caps)driver.implicity_wait(15) # 隐式等待可以设置非常高的值但是他并不会真的等这么久driver.find_element(By.XPATH,"//*[@test='交易']").click()webview = driver.contexts[-1]driver.switch_to.comtext(webview)# 执行js performance = driver.execute_script("rerurn window.performance.timing")  print(performance['domComplete']-performance['responseStart'])
复制代码


Bash 性能获取

# 在android中 运行Linux 命令adb shellvmstattop  # 一个应用的使用情况,top本身消耗性能久很大adb shell top -n 1  # 打印出一次的情况adb shell top -n 1 |grep xueqiu    # 提取出雪球的信息adb shell top -n 1 |grep xueqiu |awk '{print $3}'   # 提取出雪球appDeCPU信息;while true; do adb shell top -n 1 |grep xueqiu |awk '{print $3}'; done   # 持续提取雪球的APP CPU信息 adb shell monkey -p com.xueqiu.android -vv --throttle 300 400 # 在monkey 中设置事件百分比
复制代码

使用 appium 获取交易页面的性能数据 ,并且计算 responseStart 到 responseEnd 的时间

使用 top 提取雪球的 cpu 使用率,并循环打印


雪球 APP 专项测试实战 2

  • 综合性能(不能针对单个 app 测试)vmstat

webview 性能

耗电量

dumpsys

卡顿监测

崩溃问题

Amdahl


综合性能

adb shell vmstst
复制代码



  • 使用 bash 提取指标

adb shell vmstat | tail -l '{print $4}'while true; adb shell vmstat | tail -l '{print $4}'; done   # 循环提取某项指标
复制代码
  • appium 使用 vmstat

logging.baseconfig(level = logging.INFO)def test_vmstat():   cmd= 'adb shell vmstat'  res = subprocess.Popen(cmd , shell = True, stdout = subprecess.PPIPE,stderr = subprocess.PIPE)  print(res.stdout.read())  # 转码  logging.info(str.stdout.read(),encoding="utf-8").split("\r\n")[2].split()[3] # 第一个是0
复制代码

webview 性能

https://www.w3.org/TR/navigation-timing/#performancenavigation

下面分别实现导航,重新加载,回退的操作码

interface PerformanceNavigation {  const unsigned short TYPE_NAVIGATE = 0;  const unsigned short TYPE_RELOAD = 1;  const unsigned short TYPE_BACK_FORWARD = 2;  const unsigned short TYPE_RESERVED = 255;  readonly attribute unsigned short type;  readonly attribute unsigned short redirectCount;};
复制代码

动作模拟

window.history.back()windows.hisroey.forward()windows.location.reload()windows.location.href="https://www.baidu.com/"
复制代码

appium 中模拟 webview

def test_navigation():  caps ={}  caps["platformName"]= "Android"  caps["deviceName"]= "127.0.0.1:7555"  caps["appPackage"]="com.xueqiu.android"  caps["appActivity"]="./view.WelcomeActivityAlias"  caps['noReset'] = "true"  caps['chromedriverExecutable']="D://develop/chromedriver/2.20.exe"  driver = webdriver.Remote("http://localhost:4723/wd/hub",caps)  driver.implicitly_wait(15)  driver.find_element(By.XPATH,"//[text='交易']").click()  webview = driver.contexts[-1]  driver.switch_to.comtext(webview)  url = driver.excute_script("return window.location.href")  # 查看进入页面的操作码  print(driver.script_script("return window.performance.navigation.type"))  # 进入百度页面  url = driver.excute_script("return window.location.href='https://www.baidu.com/'")   # 变更webview页面为百度,印证 在android 高版本中webview 为Chrome内核  # 实现页面重载  driver.execute_script("window.location.reload()") # 查看操作码:1  print(driver.execute_script("return window.performance.navigation.type"))  print(url)  
复制代码

查看 webview url

  • 查看

driver.excute_script("return window.location.href")
复制代码


  • 下载

adb pull /data/user/0/com.xueqiu.android/files/h5/modules_new/xueqiu.com~/Desktop/xueqiu.com 
复制代码

日志查询

adb logcat |grep http   #显示http请求
复制代码
  • android view 对 webview 分析可以在对 APPweb 页面的远端浏览器端进行分析

耗电量

常见耗电量问题

电池会话:再次充满电之间

  • 唤醒锁(acquire)

  • 关闭屏幕,让 CPU 后台运行

  • app 长期获取唤醒锁,不释放

  • 阻止设备进入低电量模式

  • 什么样的情况唤醒锁会出问题

  • 消耗整个电池会话的 0.70%

  • 在后台运行时,消耗整个电池会话的 0.10%

  • 代码

void doSomethingAndRelease() throws MyException{	wake.acquire();  doSomethingThatThrows();  wakeLock.rerlease(); // does not run if an exception is  thrown}
复制代码
  • 改进

void doSomethingAndRelease() throws My Exception{	try{  	wakeLock.acquire();    doSomethingThatThrows();    } finally{    waleLock.release();    }  }
复制代码
  • 如何测试唤醒锁问题

  • play console

  • https://play.google.com/apps/publish/signup/#EnterDerailsPlace

  • Batteru Historian

  • dumpsys

adb shell dumpsys power
复制代码


  • 谷歌建议

  • 避免使用唤醒锁:https://developer.android.google.cn/guide/background

  • 唤醒锁改进

  • 使用前台服务

  • http://developer.android.google.cn/guide/components/services#Foreground

  • 确保锁的获取简单和释放简单

dumpsys

查看所有服务

adb shell dumpsys
复制代码

查看可用服务

adb shell dumpsys -l
复制代码

input

adb shell dumpsys
复制代码

查看输入组件(如触摸屏或内置键盘)的系统数据

  • EventHub 状态

  • input 设备在/dev/input 目录下生成节点

  • 一旦有任何输入时间产生,便会将时间写到这些节点下

  • 对于外部输入设备(鼠标键盘等)的插拔还会引起这些节点的创建和删除

  • INotify

  • Linux 提供的文件系统变化通知机制,但需要 read 读取 inotify 描述符

  • Epoll

  • 监听多个描述符的可读写 inotifyFd 状态

  • EventHub

  • 采用 INOtify+Epoll

  • 读取原始输入事件,设备增删

  • Input Reader 状态

  • 从 EventHub 读取事件,进行加工

  • 将加工好的事件发送到 InputDispatcher

谷歌官方的检测方法


  • Input Dispatcher 状态

  • 向用户发送事件

卡顿检测

测试界面性能  |  Android 开发者  |  Android Developers (google.cn)

  • 开发者选项---调试 GPU 过度渲染--- 显示过度绘制区域


  • 开发者选项---GPU 呈现模式---在屏幕上显示为条形图

帧的收集

粗糙的帧时间信息

adb shell dumpsys gfxinfo  com.tal.kaoyan
复制代码


详细的帧的情况收集

 adb shell dumpsys gfxinfo  com.tal.kaoyan frameststs
复制代码

绘制


开启后重新运行adb shell dumpsys gfxinfo com.tal.kaoyan

数据可视化--excel

python 函数-- matlotlib 图形绘制

import cmdimport subprocessdef test_draw():    cmd = "adb shell dumpsys gfxinfo  com.tal.kaoyan"    res =  subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE)    print(str(res.stdout.read(),encoding="utf-8"))    print(res.stdout.readLines())    lists = res.stdout.readLines()    i = 1    # 数据提取    for line in lines:      i+=1      if "com.xueqiu.android.common.MainActivity" in  line.decode("utf-8")      lines = [x.decode("utf-8").replace("\r\n","").replace("\t","").strip() for x in lines]      	break    # 数据处理 删除Windows特殊字符 ,提取120帧      lines = lines[i:i+120]      datas=[[] for row in range(4)]      # 把四列数据分别存入二维数组      for x in lines:        datas[0].append(float(x.split()[0]))        datas[1].append(float(x.split()[1]))        datas[2].append(float(x.split()[2]))        datas[3].append(float(x.split()[3]))      #  图片生成画布      fig = pyplot.figure()      # 折线图  第一个图片      ax1 = fig.add_subplot(2,2,1)      ax1.plot(datas[0])      ax1.set_title("draw")      # 直方图  第二个图片      ax1 = fig.add_subplot(2,2,2)      ax1.hist(datas[1],range[5])      ax1.set_title("prepare")      # 散点图  第三个图片      ax1 = fig.add_subplot(2,2,3)      ax1.scatter(range(120)datas[2])      ax1.set_title("process")      # 虚线图  第四个图片      ax1 = fig.add_subplot(2,2,4)      ax1.plot(range(120),datas[3],'k--')      ax1.set_title("execute")      pyplot.show()
复制代码

崩溃问题

ANR

  • 表现: 主线程 5S 没响应

  • 原因:

  • 当活动处于前台,app 对输入事件,广播接收器无响应 5 s

  • 当活动不在前台,广播接收器长时间执行

  • 分析

  • app 在主线程进行缓慢的 I/O 操作

  • app 在主线程进行长时间计算

  • 主线程同步绑定其它进程,其它进程长时间无响应

  • 主线程被阻塞,等待同步锁

  • 主线程处于死锁状态

  • 检测

  • play console

  • http://play.google.com/apps/publish/signup/

  • 至少一个 ANR 占所有日常 sessions 的 0.47%

  • 两个或者更多 ANR 占所有日常 sessions 的 0.24%

  • 严苛模式

  • 捕捉主线程偶然或网络访问

  • 系统检测出主线程违例的情况

  • 开发者选项中打开 show all ANRs

  • 查看 trace 日志(新版本 Android)

adb pull /data/anr/traces.txt
复制代码
  • 开发者: Take bug report


adb bugreport E:\Reports\MyBugReports
复制代码
  • Java Crash

未捕获的 android vm 异常

Amdahl 定律


用户头像

刘帅强

关注

还未添加个人签名 2019.05.14 加入

测试小白 短期计划为:构建 测试开发的全貌,而非死磕某个知识点。

评论

发布
暂无评论
APP 专项测试实战