为什么要开展压力测试?
提高产品的稳定性。
什么时候开展压力测试?
首轮功能测试通过后。
下班后的夜间进行。
什么是Monkey?
Monkey是发送伪随机用户事件的工具。
Monkey在哪里?
在手机系统里。
什么是MonkeyScript?
MonkeyScript是一组可以被Monkey识别的命令集合。
MonkeyScript可以完成重复固定的操作。
MonkeyRunner是什么?
MonkeyRunner提供了一系列的API
MonkeyRunner可以完成模拟事件以及截图操作。
Monkey和MonkeyRunner的区别?
Monkey: 在adb shell中,生成用户或系统的伪随机事件。
MonkeyRunner: 通过API定义特定命令和事件控制设备。
MonkeyRunner APIs包含什么?
MonkeyRunner:用来连接设备或模拟器。
MonkeyDevices: 提供安装、卸载应用,发送模拟事件
MonkeyImage: 完成图像保存,及对比的操作
MonkeyRunner的测试类型?
- 多设备控制
- 功能测试
- 回归测试
压力结果
- CRASH:即崩溃,应用程序在使用过程中,非正常退出。
- ANR: Application Not Responding
一个App的压测实践
- 在手机开发者选项中,将USB调试选上(部分机型还需要打开可以通过USB安装APP)
- 确认手机和电脑已经成功连接,通过adb devices命令
- 安装测试App,通过命令行adb install packageName.apk
- 发送压力指令 adb shell monkey 1000 (1000个指令的意思,具体是什么)
- 获取APP包名 adb logcat|grep START
- logcat是输入手机中一些app的log信息;
- | 代表管道的意思,将前一个命令的输出作为后一个命令的输入
- grep START 抓取包含有START的log信息输出
- 也可以输入以下命令获取设备安装的所有包名:
- adb shell pm list packages
- 给指定的包打压力 adb shell monkey -p packageName 1000
Monkey 高级参数的应用
-
throttle 参数
指定事件之间的间隔
adb shell monkey --throttle
例如: adb shell monkey -p com.android.calculator2 --throttle 1000 10
- 1000: 代表的是事件
- 10: 代表的是指令数
-
seed参数
指定随机生成数的seed值,Monkey的随机操作都是基于seed值产生的,因此使用同一个seed值就会有统一的操作序列。操作指令如下:
adb shell monkey -s
例如:adb shell monkey -s 100 50
-
触摸事件
设置触摸事件百分比。Monkey只需要完成点击事件的时候可以用本参数来设置。操作指令为:
adb shell monkey -pct-touch
例如:adb shell monkey -v -p com.android.calculator2 --pct-touch 100 10
- -v 参数可以显示执行的操作
- -p 允许添加包名作为参数
-
动作事件
设置动作事件的百分比;即monkey在手机上点击一些按钮然后松起。如果百分比为60,则剩余的会用随机操作。操作指令为:
adb shell monkey --pct-motion
例如: adb shell monkey -v -p com.android.calculator2 --pct-touch 50 --pct-motion 30 100
上述中完成50%的点击事件,然后30%的动作事件,剩余的都是随机,总共操作指令100次;
如果想只做两种操作,那么这两种操作的占比要刚好100%即可。
-
轨迹球事件
设定轨迹球事件百分比;
adb shell monkey --pct-trackball
-
基本导航事件
设定基本导航事件百分比,输入设备的上、下、左、右的导航
adb shell monkey --pct-nav
-
主要导航事件
设定主要导航事件百分比,兼容中间键、返回键、菜单键
adb shell monkey --pct-majornav
-
系统导航事件
设定系统导航事件百分比,HOME、BACK、拨号及音量键
adb shell monkey --pct-syskeys
-
启动Activity事件
设定启动Activity的事件百分比,它会在已有的activity中切换,假设设置为30%,有4个Activity,则它会在这四个总随机切换并且占总操作数的百分之30%
adb shell monkey --pct-appswitch
-
不常用事件
设定不常用事件的百分比;跟以上的事件不是一类的事件
adb shell monkey --pct-anyevent
-
崩溃事件
忽略崩溃和异常,即在发生崩溃和异常情况下,继续进行压力测试。
adb shell monkey --ignore-crashes
-
超时事件
忽略超时事件,
adb shell monkey --ignore-timeouts
综合实例:adb shell monkey -v -p com.android.calculator2 --pct-touch 50 --pct-motion 50 --ignore-crashes --ignore-timeouts 100(指定数)
CRASH结果析取
实践过程:
- 安装可以引起CRASH的App
- 执行压力命令
- 析取CRASH的Exception信息
ANR结果析取
安装可以引起ANR的app
执行压力命令
-
析取ANR的Exception信息
如果是手动的触发的ANR信息,可以先输入adb shell进入手机,然后cd /data/anr文件夹下面有日志记录,找到该ANR即可。自动化的可以直接在命令后面加 > log.log 即可输出到文件。
Monkey Script
重复操作序列100次的需求时,通过MonkeyScript可以实现。执行MonkeyScript的命令是:
adb shell monkey -f
-
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)
- downtime: 键最初被按下的事件
- eventide:指的事件,发生的事件
- action :某个操作,具体的是按下还是弹起的过程(重点)
- 0 代表按下
- 1 代表弹起
- 因此一条点击事件需要两条指令,一个按下,一个弹起
- x,y: 坐标点(重点)
- 代表坐标点,通过UiAutomator工具来获取点击的坐标值
- pressure:当前压力事件的大小,范围是0-1
- size:触摸的一个既是值,范围也是0-1
- metastate:当前按下meta键的标识
- xprecision/yprecision:x/y坐标的精确值
- device: 事件的来源,范围0-x, 0表示不来自物理设备
- edgeflags:超出了屏幕的范围
-
DispatchPointer
命令点击事件
DispatchPointer(long downtime, long eventide, int action, float x, float y, float pressure, float size, int metastate, float xprecision, float yprecision, int device, int edgeflags)
参数含义如上。
-
DispatchString
命令
输入字符串事件
DispatchString(String text)
-
LaunchActivity
命令启动应用
LaunchActivity(package, Activity)
-
UserWait
命令等待事件
UserWait(1000) // 毫秒
-
DispatchPress
命令按下键值
DispatchPress(int keycode)
# keycode 66 回车键
-
实例:在搜索框输如查询词
- 启动App
- 点击输入框
- 输入查询词
- 点击键盘上的回车
- 点击搜索按钮
- 等待结果的输出
- 点击clear按钮,保证重复的时候不会还有词在
typ=user
count=10
speed=1.0
start data >>
LaunchActivity(com.example.zhangjian.mibirowser2, com.example.zhangjian.mibirowser2.MainAcitivity) //1
UserWait(2000)
DispatchPointer(10,10,0,100,100,1,1,-1,1,1,0,0) //2 按下,100,100是xy坐标值,通过UiautomatorView测试得出
DispatchPointer(10,10,1,100,100,1,1,-1,1,1,0,0) //2 弹起
DispatchString(test) // 3
UserWait(1000)
DispatchPree(66) // 4
UserWait(1000)
DispatchPointer(10,10,0,400,100,1,1,-1,1,1,0,0) //5 按下
DispatchPointer(10,10,1,400,100,1,1,-1,1,1,0,0) //5 弹起
UserWait(6000) // 6
DispatchPointer(10,10,0,300,100,1,1,-1,1,1,0,0) //7 按下
DispatchPointer(10,10,1,300,100,1,1,-1,1,1,0,0) //7 弹起
UserWait(3000)
保存文件为mook.script,以.script结尾的后缀名
将桌面的脚本传输到手机里,通过命令:adb push mook.script /data/local/tmp/
输入adb shell 然后cd到/data/local/tmp/这个文件夹;
输入 monkey -f mook.script 2(次数)
完成上述后会发现启动的并不是我们想要启动的app,而是一个超级用户,这是为什么呢?
因为app的本身AndroidManifest.xml文件中,主activity缺少一个android:exproted=“true”的属性,没有这个属性那么app本身是不允许在外部被调起,也就是无法通过命令行来调起该activity.
MonkeyRunner
MonkeyScript也存在缺点,它在执行过程中无法实现截屏操作,有时候在进行自动化测试的过程中需要进行截屏,这个时候MonkeyScript就无法满足了。此时可以用MonkeyRunner来解决了。
- MonkeyRunner API - alert (python类型的脚本)
警告框,用法:
void alert(string message, string title, string okTitle)
实例:demo.py
from com.android.monkeyrunner import MonkeyRunner
MonkeyRunner.alert("Hello mook friends","this is title", "OK")
运行: monkeyrunner demo.py
- MonkeyRunner API - waitForConnection
等待设备连接,有多个device id, 需要指明具体哪个设备。使用指令为:
waitForConnection(float timeout, string deviceid)
- MonkeyRunner API - drag
拖动。在页面实现拖动的这样的一个操作,其使用指令如下:
drag(tuple start, tuple end, float duration, integer steps)
start:拖动的起始点
end:拖动的结束位置
duration:手势持续的时间
steps:插值点的步数,默认10
- MonkeyRunner API - press
按键。使用操作如下:
press(string keycode, dictionary type)
keycode:名,Down,Up,DOWN_AND_UP
- MonkeyRunner API - startActivity
启动应用。使用指令如下:
startActivity(packageName+'/'+activity)
- MonkeyRunner API - touch
点击。使用指令如下:
touch(integer x, integer y, integer type)
x,y: 坐标值
type: DOWN, UP, DOWN_UP
-
MonkeyRunner API - type
输入。使用指令如下:
type(string message)
-
MonkeyRunner API - takeSnapshot
截屏,这是MonkeyRunner提供的一个强大的操作,其使用指令如下:
MonkeyImage takeSnapshot()
它会返回一个MonkeyImage类型的数据
-
MonkeyRunner API - sameAs
图像对比。如果需要对比两幅图像,其使用指令如下:
boolean sameAs(MonkeyImage other, float percent)
- MonkeyRunner API - writetoFile
保存图像文件,使用指令为:
void writeToFile(string path, string format)
实例: 实现在搜索框中输入查询词,并截图
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
# 连接设备
device = MonkeyRunner.waitForConnection(3,"192.168.56.101:5555") #"192.168.56.101:5555"为手机名称,3代表操作时间3秒
# 启动app
device.startAcitivyt("com.example.zhangjian.minibrowser2/com.example.zhangjian.minibrowser2.myapplication.MainActivity")
MonkeyRunner.sleep(2) #单位为秒
# 点击搜索框
device.touch(100,100,"DOWN_AND_UP")
MonkeyRunner.sleep(1)
# 输入查询词
device.type("test")
MonkeyRunner.sleep(1)
# 点击回车键
device.press("KEYCODE_ENTER","DOWN_AND_UP")
MonkeyRunner.sleep(1)
# 点击搜索按钮
device.touch(400,100,"DOWN_AND_UP")
MonkeyRunner.sleep(6)
# 截图
image = MonkeyImage.takeSnapshot()
image.writeToFile("./test.png","png")
# 点击清除按钮
device.touch(300,100,"DOWN_AND_UP")
MonkeyRunner.sleep(3)