前言:写这篇文章的目的,一是因为不少同学作为Android开发,很少会自己去做压力测试,不了解相关的技术,不知道压力测试是什么、怎么工作的;二是询问过身边的一些测试同学,他们进行压力测试的时候,很多情况只是执行monkey的随机操作,也有部分同学不会写测试脚本,那么本篇文章就应运而生了!

一、背景

1.为什么要进行压力测试?

我们都知道一款产品上线之前都需要进行的一步操作就是测试验收,那么人工手动的测试是带有一定的偶然性的,因为没有人知道哪一步操作会出现问题(例如Crash、ANR等),还有对于一些偶发现象,人为难以复现的场景,开发人员无法针对性的解决问题,那么进行压力测试就是尽可能的模拟各种使用场景,最大程度发现隐藏的问题。

压力测试的目标:

  • 1.提高产品稳定性
    产品的稳定性是App产品所有指标中非常重要的一项,有机构统计70%的用户在使用App时会遇到各种不稳定的问题,当出现异常问题时,有的用户会忍受继续使用,有的用户可能就会放弃使用直接卸载App了,这取决于应用的使用场景和发展阶段,例如微信、QQ、支付宝等等,人们已经离不开这些和生活息息相关的产品了,哪怕偶尔出现一两次不稳定的问题,用户很大程度上也不会卸载,但是如果这发生在一款初创期的App上,用户可能直接就卸载了,可能给公司带来致命的打击。

  • 2.提高产品留存率
    机构统计有5%的用户在遇到页面延时响应时间过长的时候,会选择放弃继续使用或者卸载App,当用户对这样的一款App产生反感情绪时,产品的DAU和留存率就会降低。所以提高产品的稳定性、提高产品的留存率,为公司带来更大的收益,压力测试势在必行!

2.什么时候进行压力测试?

这个没有明确的要求,但是一般会选择在首轮功能测试验收通过后进行,这样能最大程度避免因为功能性bug导致的压力测试结果异常。因为压力测试是自动化执行,所以当我们下班的时候,就可以执行测试脚本,第二天早上上班的时候来查看压力测试结果,测试工作互不耽误。

二、理论

1.手工测试场景


当我们手工模拟一个搜索操作时,会按照以上的步骤来:1.点击搜索框(弹起软键盘),2.输入关键词,3.点击搜索按钮,搜索结果就会出现在下面的网页中。

2.自动测试场景

将我们上述的手工操作,转换成机器语言,应该是什么样呢?

点击输入框 -> 输入关键词(键盘事件)-> 点击搜索 -> 选择想要查看的结果条目 -> 滚动浏览,这就是机器自动化的流程,那么我们应该做的就是模拟手工操作的事件流。

3.Monkey工具

  • 1.什么是Monkey?
    Monkey是Android SDK自带的测试工具,是一个命令行工具,可以运行在模拟器里或实际设备中。可以运行在模拟器中或者实际设备中,它向系统发送伪随机的用户事件流(如按键输入,触摸屏输入,手势输入等),实现对正在开发的应用程序进行压力测试。由于测试事件和数据都是随机的,不能自定义,所以有很大的局限性。
  • 2.Monkey在哪儿?
    存在于我们的Android手机中,需要借助ADB来和Monkey进行通信。

4.ADB命令

  • 1.什么是ADB?
    Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信。adb 命令便于执行各种设备操作(例如安装和调试应用),并提供对 Unix shell(可用来在设备上运行各种命令)的访问权限。
  • 2.ADB在哪儿?
    adb 包含在 Android SDK 平台工具软件包中。您可以使用 SDK 管理器下载此软件包,管理器会将此软件包安装在 android_sdk/platform-tools/。或者,如果您需要独立的 Android SDK 平台工具软件包,可以点击此处进行下载。

5.什么是MonkeyScript

MonkeyScript是官方提供的,除了像猴子一样随机乱点之外,还可以通过编写脚本的形式,完成一系列固定的操作。MonkeyScript提供一整套完善的API来进行支持,主要还是基于坐标点的操作,包含常用的:点击、长按、输入、等待等操作。

6.什么是MonkeyRunner

monkey和monkeyrunner都是android sdk提供的测试命令,但monkeyrunner和money没有什么直接的关系,monkey是在设备直接运行adb shell命令生成随机事件来进行测试的。相比较而言,monkeyrunner则是通过API发送特定的命令和事件通过工作站来控制设备。

7.MonkeyRunner API

MonkeyRunner工具主要有三个类:MonkeyRunner、MonkeyDevice、MonkeyImage。

  • 1.MonkeyRunner类:提供连接真机和模拟器方法waitForConnection(float timeout,string deviceid),还有显示提示显示信息的alert()方法。
  • 2.MonkeyDevice类:提供了安装和卸载程序包、开启Activity、发送按键和点击事件、运行测试包等方法。
  • 3.MonkeyImage类:在测试过程中用来保存测试截图,保存各种格式,并可以比较两个MonkeyImage对象。

三、实战

1.App压力测试实战

  • 1.在手机开发者选项中,将USB调试勾选。
  • 2.确认手机和电脑已经成功连接。

    在连接设备列表中能发现自己的设备说明连接成功。
  • 3.安装测试App
  • 4.发送压力测试命令(随机)
adb shell monkey 100

这时手机就会模拟各种随机操作100次。

执行完后在命令行会看到以下内容:

可以看到我们设置的是执行100次操作,这里Events injected也收到了100次事件,说明过程中没有出现异常,否则Events injected数量会少于100,整个操作过程耗时5613ms。

  • 5.获取App包名
    以上我们执行的是随机命令,如果我们想针对某一个App进行压力测试怎么办呢?首先我们需要获取想要测试的App的包名,可以借助以下一行命令:
adb logcat | grep START

这里拿计算器应用为例,执行后,然后点击手机中的计算器应用,就会发现在最后一行会输出计算器的相关信息:

其中cmp=com.meizu.flyme.calculator就是计算器的包名了。

  • 6.给指定App进行压力测试
adb shell monkey -p com.meizu.flyme.calculator 1000

这行代码会对我们的计算器应用执行1000次的随机操作。

2.Monkey高级参数的使用

  • 1.throttle参数
    指定事件之间的间隔(毫秒)
adb shell monkey --throttle <milliseconds>
  • 2.seed参数
    指定随机生成数的seed值
adb shell monkey -s <seed> <event-count>

我们利用monkey进行压力测试的时候,monkey生成的事件流都是随机的,如果在执行过程中发生异常的时候,测试同学可能找开发去修改,开发同学要求测试同学复现操作步骤,那么这个时候就很难复现了。如果我们能够指定seed值的话,那么monkey就会执行相同的操作序列,就能很方便的复现之前出现的异常问题。

  • 3.触摸事件
    设定触摸事件百分比
adb shell monkey --pct-touch <percent>

同样以计算器为例,在命令中增加一个-v参数,能够看出操作执行过程中的百分比:

Event 0代表的是touch事件,因为我们指定了–pct-touch 100,所以其他的触摸事件都是0,touch事件是100,另外下面的结果中出现了多次ACTION_DOWN和ACTION_UP,按下和弹起都是配对出现的,这就是模拟一次点击过程。

如果我们不指定–pct-touch 100,来看看执行效果:

可以看出事件很随机的分布,其中touch事件占了15%,从下面打出的日志可以看出,还有像Traceball和rotation这些事件的触发。

  • 4.动作事件
    设定动作事件百分比
adb shell monkey --pct-motion <percent>

这里需要注意一点是动作事件和其他事件百分比的和要等于100,如果不等于100的话,则会将剩余部分随机操作。

这里我们指定了touch事件50%,motion事件30%,所以剩下的8种事件类型占比是随机分配的。

  • 5.轨迹球事件
    设定轨迹球事件百分比
adb shell monkey --pct-traceball <percent>
  • 6.基本导航事件
    设定基本导航事件百分比,输入设备的上、下、左、右
adb shell monkey --pct-nav <percent>
  • 7.主要导航事件
    设定主要导航事件百分比,兼容中间键、返回键、菜单键
adb shell monkey --pct-majornav <percent>
  • 8.系统导航事件
    设定系统导航事件百分比,HOME、BACK、拨号和音量键
adb shell monkey --pct-syskeys <percent>
  • 9.启动Activity事件
    设定启动Activity事件百分比,会在多个app之间进行切换
adb shell monkey --pct-appswitch <percent>
  • 10.不常用事件
    设定不常用事件百分比
adb shell monkey --pct-anyevent <percent>
  • 11.崩溃事件
    忽略崩溃和异常

在monkey执行过程中,如果遇到一次crash,则进程会中断,不会继续往下进行,那么我们如果希望monkey能够执行完所有的事件的话,就需要用到这个参数。

adb shell monkey --ignore-crashes <event-count>
  • 12.超时事件
    忽略超时事件

和崩溃事件一样,如果monkey遇到ANR时,也会中断,所以我们需要忽略超时事件的话,可以用到这个参数。

adb shell monkey --ignore-timeouts <event-count>

3.Crash结果分析

  • 1.安装一个会发生Crash的app
  • 2.执行monkey进行压力测试
  • 3.分析Crash的Exception信息


可以看到当monkey触发了某一个crash事件时,进程停止了,同时会打印出crash的相关信息,这是Event injected事件是533,我们命令中指定的是1000,所以当异常发生时,不会继续执行剩下的操作。

注意到在log的最后有一行:

System appears to have crashed at event 533 of 1000 using seed 1574782034909

前面我们说过,如果我们想要重复上一次的过程的话,需要指定一个seed值去模拟上一次的操作,这里可以使用seed 1574782034909,这样执行过程就会和上次一模一样,这样就可以复现我们刚才崩溃的场景。

如果我们希望出现crash时,monkey仍然执行完1000次操作时,这时就可以用到上面介绍到的–ignore-crashes。

可以看到,我们指定了seed,模拟上一次的操作流,同时也使用了–ignore-crashes,crash发生了,但是仍会执行完,所以Event injected为1000,但是这个时候想看到seed值会发现没有了,因为当crash发生时,仍然要求monkey继续执行,所以就会随机生成一个新的seed值。

4.ANR结果分析

  • 1.安装一个会发生ANR的app
  • 2.执行monkey进行压力测试
  • 3.分析ANR的Exception信息

日志非常多,截取部分日志来看看:


可以看到当执行到第84个操作时,就发生了ANR,发生的原因在日志中也有具体的描述,如果我们希望复现这个ANR的话,可以依靠此次产生的seed。同理如果希望事件继续执行完,可以借助–ignore-timeouts命令。

5.MonkeyScript实战

在monkey帮我们完成稳定性测试之后,我们如果有一种需求,模拟重复操作事件流100次,而monkey是随机操作,那么这时候就要使用MonkeyScript了。

adb shell monkey -f <script-file> <event-count>

在编写MonkeyScript之前,来先了解一些常用命令:
1.DispatchTrackball命令
轨迹球事件

DispatchTrackball(long downtime,long eventide,int action,float x,float y,
float pressure,float size,int metastate,float xprecision,float yprecision,
int device,int edgeflags)

long downtime指键最初被按下的时间
long eventtide指事件发生的时间
int action指具体操作的动作,如按下
float x,float y指x和y的坐标
float pressure压力事件的大小(0~1)
float size指触摸的记事值(0~1)
int metastate指当前按下mate键的标识
float xprecision,float yprecision指x和y坐标的精确值
int device事件的来源(0~x)
int edgeflags指超出屏幕了范围

我们这里用三个参数就可以了,分别是:
int action(0表示按下,1表示弹起)
如果我们想要模拟点击事件的话,需要传输两个参数,一个命令传输0,表示按下,另一个传输1,表示弹起,这样我们可以实现点击的过程。

在点击的过程中,我们需要确定点击的点,这里就是指需要确定点击的范围,即就是x和y的坐标:float xfloat y

2.DispatchPointer命令
点击事件

DispatchPointer(long downtime,long eventtide,int action,float x,float y,
float pressure,float size,int metastate,float xprecision,float yprecision,
int device,int edgeflags)

参数含义和DispatchTrackball一样。

3.DispatchString命令
输入字符串命令

DispatchString(String text)

接收一个要输入的字符串。

4.LaunchActivity命令
启动应用

LaunchActivity(package,Activity)

#package指App包名
#Activity指被启动页面的名称

5.UserWait命令
等待事件

UserWait(1000)

等待的时间,单位为毫秒

6.DispatchPress命令
按下键值

DispatchPress(int keycode)

keycode 66 回车键
根据自己的需要传入具体对应的键值即可

MonkeyScript实战部分
在了解完上述的几个命令之后,我们正式开始编写脚本。这里我们模拟一个用户在浏览器搜索100次的场景。用户每次的操作流程如下:

那我们将这几个步骤转化为MonkeyScript支持的语言。

首先MonkeyScript有一些固定的脚本头,需要写在脚本的最前面。

type=user
count = 1
speed = 1.0
start data >>

然后才是我们要执行的步骤脚本,完整的脚本如下:

type=user
count = 1
speed = 1.0
start data >>LaunchActivity(com.zhangyan.monkeydemo,com.zhangyan.monkeydemo.MainActivity)
UserWait(2000)
DispatchPointer(10,10,0,200,200,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,200,200,1,1,-1,1,1,0,0)
DispatchString(China)
UserWait(1000)
DispatchPress(66)
UserWait(1000)
DispatchPointer(10,10,0,1350,250,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,1350,250,1,1,-1,1,1,0,0)
UserWait(6000)
DispatchPointer(10,10,0,1200,250,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,1200,250,1,1,-1,1,1,0,0)
UserWait(3000)

解释一下参数:

DispatchPointer(10,10,0,200,200,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,200,200,1,1,-1,1,1,0,0)

这是一个模拟点击事件,所以按下和弹起是成对出现的,第三个参数action分别是0和1表示down和up,第四位和第五位参数是点击的x和y坐标点,那么这个点如何获取呢?需要借助Android SDK中的一个uiautomatorviewer,它的路径在我的/Library/Android/sdk/tools/bin/下,你们可以在你们对应的安装目录下找到这个命令。运行起来后如下所示:

我们可以借助这个获取我们想要的x和y值,放到参数中就行了。

脚本写完了保存一下,此时执行adb shell monkey -f monkey.script 2是无效的,为什么呢?
因为monkey是存在我们的手机设备中的,而我的monkey.script脚本存在我的电脑中的,所以手机中的monkey是无法直接获取到电脑设备的脚本的,所以我们需要将monkey.script放到手机中去,执行以下这段命令:

adb push monkey.script /data/local/tmp/

然后执行这条命令,注意路径得写文件的绝对路径,也就是我们刚才设置的路径。

adb shell monkey -f /data/local/tmp/monkey.script 2


可以看到脚本执行起来后,app就会按照我们设定的操作执行,重复的次数就是我们设置的2次,当操作全部执行完成后,终端会有如下信息:

那么这里为什么Event injected等于30呢?其实这个操作的个数就是我们脚本里的命令数,执行多少次就是它的乘积。

6.MonkeyRunner实战

MonkeyScript虽然很强大,能够帮助我们完成丰富的操作,但是它也有很多限制之处,比如我们在自动化过程中想要完成截屏操作,那它就无法完成了,此时就需要用到MonkeyRunner了。

在使用MonkeyRunner之前,来先了解一些常用命令。

MonkeyRunner API 主要通过下面三个包:
MonkeyRunner: 主要提供了MonkeyRunner应用的辅助方法以及用来连接设备或是模拟器的方法,并提供UI支持等。
MonkeyDevice: 代表一个设备或是模拟器,提供安装、卸载应用的方法,启动一个 Activity,发送按键或是Touch事件等。
MonkeyImage: 代表一个截屏图像,可以截取不同格式的图像,比较两个MonkeyImage图像,保存图像等。

1.MonkeyRunner API - alert
警告框

void alert(String message,String title,String okTitle)

下面来写一段python脚本:

#!/usr/bin/python
#-*- UTF-8 -*-
from com.android.monkeyrunner import MonkeyRunner
MonkeyRunner.alert('Hello World','MonkeyRunner','OK')

执行命令monkeyrunner demo.py

2.MonkeyRunner API - waitForConnection
等待设备连接,有多个device id,需要指明具体哪个设备

waitForConnection(float timeout,String deviceId)//timeout单位为秒

3.MonkeyRunner API - drag
拖动

drag(tuple start,tuple end,float duration,integer steps)

start:启动位置
end:终点位置
duration:手势持续的时间
插值点的步数,默认是10

4.MonkeyRunner API - press
按键

press(String keycode,dictionary type)

keycode:按键的code
type:按键类型:DOWN、UP、DOWN_AND_UP

5.MonkeyDevice API - startActivity
启动应用

startActivity(package+"/"+activity)

6.MonkeyDevice API - touch
点击事件

touch(integer x,integer y,integer type)

7.MonkeyDevice API - type
输入事件

type(String message)

8.MonkeyDevice API - takeSnapshot
截屏事件

MonkeyImage takeSnapshot()

9.MonkeyImage API - sameAs
图像对比

boolean sameAs(MonkeyImage other,float percent)

10.MonkeyImage API - writeToFile
保存图像文件

void writeToFile(String path,String format)

MonkeyRunner实战部分
我们仍然模拟上面的操作,用MonkeyRunner脚本来实现一遍,完整代码如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage
#连接设备
device = MonkeyRunner.waitForConnection(3,"793QADSKAR5G4")
#启动app
device.startActivity("com.zhangyan.monkeydemo/com.zhangyan.monkeydemo.MainActivity")
MonkeyRunner.sleep(2)
#点击搜索框
device.touch(200,200,"DOWN_AND_UP")
MonkeyRunner.sleep(1)
#输入关键词
device.type("China")
MonkeyRunner.sleep(1)
#点击回车键
device.press("KEYCODE_ENTER","DOWN_AND_UP")
MonkeyRunner.sleep(1)
#点击搜索
device.touch(1350,250,"DOWN_AND_UP")
MonkeyRunner.sleep(3)
#截图
image = device.takeSnapshot()
image.writeToFile('./takeSnapshot.png','png')
#点击清除按钮
device.touch(1200,250,"DOWN_AND_UP")
MonkeyRunner.sleep(3)

我的python脚本放在桌面上,所以进入到桌面目录,执行以下命令:

monkeyrunner monkeyrunner.py

等待几秒设备连接成功,就会看到手机出现和MonkeyScript一样的操作,不过我们的python脚本中有一个截屏的操作,等待脚本执行完,会看到桌面上有一张我们命名好的图片,打开看看图片的内容:

可以看到在我们点击搜索按钮后,就执行了截屏命令,保存到指定路径。

到这里MonkeyRunner的基本用法就讲完了,我们可以看到MonkeyRunner帮助我们完成了整个自动化的过程,如果想要MonkeyRunner执行多次的话,就需要借助python脚本做这样的事情,这样可以完成重复的操作过程。

四、结束语

这篇文章简单的介绍了Monkey相关的知识,包括基础的MonkeyScript使用、MonkeyRunner的使用,大家可以借助这些命令实现自己的一个自动化压力测试的功能,感谢!

Android App压力测试相关推荐

  1. Android App 压力测试 monkeyrunner

    Android App 压力测试 第一部分 背景 1. 为什么要开展压力测试? 2. 什么时候开展压力测试? 第二部分 理论 1. 手工测试场景 2. 自动测试创建 3. Monkey工具 4. AD ...

  2. Android APP压力测试(二) 之Monkey信息自动收集脚本

    转载-原文地址:   http://www.cnblogs.com/findyou/p/3936063.html Android APP压力测试(二) 之Monkey信息自动收集脚本 前言: 本文重点 ...

  3. Android App压力测试(Monkey和ADB)

    压力测试简介 压力测试是一种基本的质量保证行为,它是每个重要软件测试工作的一部分.压力测试的基本思路很简单:不是在常规条件下运行手动或自动测试,而是在计算机数量较少或系统资源匮乏的条件下运行测试.通常 ...

  4. Android App压力测试(慕课网学习笔记)

    转载:https://blog.csdn.net/a923751813/article/details/72884826 一  背景 1. 为什么开展压力测试 目标1:提高产品稳定性(产品稳定性是一项 ...

  5. Android App专项测试-压力测试篇

    小伙伴们大家好,今天主要分享的主题是Android App专项测试.如何进行Android App专项测试压力测试呢?我们主要通过Android平台的一门工具Monkey.在学习本门课程之前,如果你具 ...

  6. android monkey压力测试(二)

    一.什么是Monkey 顾名思义,Monkey就是猴子,  Monkey测试,就像一只猴子, 在电脑面前,乱敲键盘在测试.  猴子什么都不懂, 只知道乱敲 通过Monkey程序模拟用户触摸屏幕.滑动T ...

  7. Android Monkey压力测试

    一. JAVA环境的搭建 安装jdk-8u151-windows-x64,可以到官网或者应用中心下载. JAVA环境变量的搭建: 在"我的电脑"-"属性"-&q ...

  8. android monkey压力测试,Android-Monkey 压力测试

    1.Monkey 介绍 Monkey是Android中一个对App进行压力测试的命令行工具,可以向系统发送伪随机的用户事件流对正在开发的App进行压力测试(模拟用户操作App).压力测试主要是为了提高 ...

  9. APP压力测试工具使用

    Monkey Monkey 是一个 Android 自动化测试小工具.(压力性能测试) 主要用于Android 的压力测试, 主要目的就是为了测试app 是否会Crash崩溃. Monkey测试教程 ...

最新文章

  1. 简单的Socket实现web功能
  2. 在JavaScript中删除对象
  3. 9月20日 DNS总结
  4. 拥抱 Android Studio 之五:Gradle 插件开发
  5. 【C#】多线程解决UI界面卡死的问题
  6. 关于Jbulder2006的问题
  7. easyui tree的简单使用
  8. pandas创建DataFrame
  9. PX4从放弃到精通(十八):参数
  10. Freertos消息队列接收源码xQueueGenericReceive分析
  11. Elasticsearch集群规划及节点角色规划醉佳实践
  12. LSF Command
  13. pandas模块DataFrame数据结构行数据的获取
  14. java毕业设计汽车维修管理系统源码+lw文档+mybatis+系统+mysql数据库+调试
  15. 加入合作伙伴计划应留意的5个危险信号
  16. Fiddler抓包软件[一]下载与安装
  17. 从零开始实现一个量化回测系统(一)
  18. vscode保存自动格式化加逗号解决方法
  19. 基于BGP技术和防火墙双机热备技术的校园网设计与实现
  20. 显卡知识扫盲 为你讲述流水线的发展与未来

热门文章

  1. spring boot + vue 前后端下载文件文件
  2. 2016年9月下旬校园招聘面经(美团、百度、58同城、华为、微店 11月10号更新)
  3. Hello China V1.75版本运行截图
  4. python2.7的字符串拼接
  5. 正则表达式 - 自动生成器
  6. csr867x入门之按键配置(九)
  7. 噩梦射手(SurvivalShooter)教程(十一)
  8. 怎么判断时double和floatc++_痛心!血肌酐正常却已经肾衰?如何判断肾功能,这些指标更准确...
  9. HCIA网络课程第一周作业
  10. 8种提升程序猿编程能力的方法+编程思维四个核心:分解、抽象、模式识别和算法