Android自动化测试入门(一)Monkey和MonkeyRunner
测试是应用开发中不可或缺的一部分。测试所做的工作,虽然不能让用户看到效果,但是想要保证一个有一定用户基础的应用的稳定性,测试是必须做的,否则严重的崩溃率肯定会导致用户的差评或者流失。
ADB工具使用
ADB的使用Android开发者应该都很熟悉了,它是电脑和手机之间连接的一个桥梁。电脑端有一个Client和一个Server,Client负责输入命令,Server负责和手机连接,手机端通过adbd跟Server交互
常用的ADB命令
adb devices
列出电脑连接的设备 和 设备id,设备状态adb push
电脑端推送文件到手机 比如adb -s 设备名 push 1.jpg /data/temp/1.jpg
如果连接了一个设备可以不用自定设备名称
adb pull
从手机拉取文件到电脑 比如adb -s 设备名 pull /data/temp/1.jpg /data/11.jpg
adb forward
端口转发 比如 adb forward tcp:11111 tcp:22222的意思是,将PC端的11111端口收到的数据,转发给到手机中22222端口adb start-server/adb kill-server
启动/杀死ADB服务adb install/adb uninstall
安装/卸载 apk uninstall命令需要指定应用的包名adb shell
可以在电脑上直接进入手机终端界面操作手机
进入adb shell之后 使用 pm list packages
可以列出手机上是所有包名
android命令可以用来查看当前Android开发环境中的系统信息和操作。主要有
android sdk
查看sdkandroid avd
模拟器相关,android list
列表 比如android list target
列出所支持的Android平台,android list avd
列出所有的模拟器android create project
创建一个Android工程。
把sdk/tools路径配置到环境变量中或者直接进入sdk/tools目录中执行这些命令即可。
Monkey 工具
Monkey是Andorid系统中自带的一个黑盒测试工具,可以产生伪随机事件(点击、轻触)流。一般是通过随机触发界面事件,来确定是否发生了异常。一般用于Android应用的稳定性、压力测试
简单使用
Monkey是一个命令行工具,可以在任何模拟器或者设备上运行,将伪随机事件流发送到系统中来进行压力测试。 需要通过adb shell来启动,命令格式1
adb shell monkey [option] <event-count>
各种参数的作用官网上有详细文档:官网地址
下面进入adb shell中做一个小例子:
通过pm list packages
命令可以看到手机中所有的包名,可以随便找一个测试,这里使用系统计算器来测试它的包名是com.android.calculator2
。
可以执行下面的命令,来执随机行应用1000次
1 | monkey -p com.android.calculator2 1000 |
可以通过-v 来输出执行日志,比如
1 | monkey -p com.android.calculator2 -v -v 100 |
-v的个数表示日志输出的级别,最多三个,越多日志越详细来看看输出的日志1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33data="com.android.calculator2"
//使用monkdy工具 测试了100次
//通过-s指定seed的值可以重复跟本次操作一模一样的操作
:Monkey: seed=1582553186510 count=100
//测试的包名
:AllowPackage: com.android.calculator2
//策略
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
// Selecting main activities from category android.intent.category.LAUNCHER
// + Using main activity com.android.calculator2.Calculator (from package com.android.calculator2)
// Selecting main activities from category android.intent.category.MONKEY
// Seeded: 1582553186510
// Event percentages:
//每一种事件测试的占比,每个数组代表不同的事件类型
//
// 0: 15.0%
// 1: 10.0%
// 2: 2.0%
// 3: 15.0%
// 4: -0.0%
// 5: -0.0%
// 6: 25.0%
// 7: 15.0%
// 8: 2.0%
// 9: 2.0%
// 10: 1.0%
// 11: 13.0%
.....
//网络状况 执行时间
## Network stats: elapsed time=484ms (0ms mobile, 0ms wifi, 484ms not connected)
// Monkey finished
日志最开始有个输出seed=1582553186510
,通过这个值我们可以重新执行一次一模一样的当前操作adb shell monkey -s 1487572980979 -v 1000
1-11的占比代表各种事件的执行比例,比如轻触事件,手势事件,缩放事件,导航事件,屏幕旋转事件等在MonkeySourceRandom这个类中有常量表示。下面是Android 9.0源码中的数值常量。1
2
3
4
5
6
7
8
9
10
11
12public static final int FACTOR_TOUCH = 0; //轻触
public static final int FACTOR_MOTION = 1; //滑动
public static final int FACTOR_PINCHZOOM = 2; //缩放
public static final int FACTOR_TRACKBALL = 3; //轨迹球
public static final int FACTOR_ROTATION = 4; //旋转
public static final int FACTOR_PERMISSION = 5; //权限
public static final int FACTOR_NAV = 6; //基本导航 上下左右键等
public static final int FACTOR_MAJORNAV = 7; //主要导航(一般会导致UI变化) 回退键 菜单键等
public static final int FACTOR_SYSOPS = 8; //系统事件
public static final int FACTOR_APPSWITCH = 9; //activity启动事件
public static final int FACTOR_FLIP = 10; //键盘翻转
public static final int FACTOR_ANYTHING = 11; //其他事件
如果执行过程中发生了崩溃,Monkey会停在崩溃的地方,使用--ignore-crashes
可以在崩溃的时候继续执行后序操作adb shell monkey —ignore-crashes 1000
。
程序ANR对于andorid应用来说是一个比较严重的问题,Monkey在执行中遇到ANR的时候会停止,执定--ignore-timeouts
参数可以让monkey继续执行adb shell monkey --ignore-timeouts 1000
。
使用>
符号将日志输出到特定的文件中查看比如adb shell monkey —ignore-crashes 1000>d:\monkey.txt
,此文件中会告诉我们那个地方出了问题,具体的错误日志可以通过adb bugreport
命令将运行日志导出来查看更详细的信息
1 | //6.0及以下设备 |
Monkey 脚本
有时候我们不想让它随机执行,通过脚本可以让测试按照我们自定义的流程来执行。使用-f参数就可以执行Monkey的脚本了adb shell monkey -f <script> 1
官网没有介绍Monkey脚本的使用的文章,可以参照sdk源码中的写法。在MonkeySourceScript.java这个类中可以参考。
Monkey脚本的主要命令:
- DispatchPointer(downtime,eventTime,action,x,y,xpressure,size,metastate,xPrecision,yPrecision,device,edgeFlags):手势操作,相当于手指按到某个位置。参数x,y是手指按下的坐标位置,坐标位置可以通过DDMS中的工具UI Automator来获取,位置在sdk/tools/monitor中
- DispatchPress[keycode] 按下系统的某个固定的按键,比如home键,back键等,在官网KeyEvent这个类中有对每种keycode含义的详细介绍。
- LaunchActivity(pkg_name, cl_name): 用来启动应用 参数是 包名+类名
- UserWait:让脚本暂停一段时间
- UserWait(sleepTime):指定睡眠时间
- RotateScreen(rotationDegree, persist):参数是旋转角度+旋转后是否停在当前位置。0代表0度 1代表90度 2代表180度 3代表 270度;第二个参数 0表示旋转后恢复,非0则表示固定不变
- Tap(x, y,tapDuration):单击时间 x y 是点击屏幕的坐标 点击的时长
- Drag(xStart, yStart, xEnd, yEnd):在屏幕上滑动参数是滑动坐标的起始点
- LongPress(): 长按2s
- ProfileWait(): 等待5s
- PressAndHold(x, y, pressDuration) :模拟长按
- PinchZoom(x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End, stepCount): 模拟缩放
- DispatchString(input): 输入字符串
- RunCmd(cmd) :执行shell命令,比如截图 screencap -p /data/temp/temp.png
- DispatchFlip(true/false) :打开或者关闭软键盘
- DeviceWakeUp() :唤醒屏幕
获取某个界面元素在屏幕上的坐标使用sdk中的工具uiautomatorviewer.bat位置在sdk/tools/bin/uiautomatorviewer.bat,双击即可运行如下。
开始编写脚本测试系统计算器 定义一个脚本文件monkey.script1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33type= raw events
count= 10
speed= 1.0
start data >>
LaunchActivity(com.android.calculator2,com.android.calculator2.Calculator)
#点击 6
#使用DispatchPointer(downtime,eventTime,action,x,y,xpressure,size,metastate,xPrecision,yPrecision,device,edgeFlags)来完成
#第三个参数action 0是按下 1是抬起
#使用sdk中的uiautomatorviewer.bat工具来获取x y的坐标 sdk/tools/bin/uiautomatorviewer.bat
DispatchPointer(0,0,0,600,1200,0,0,0,0,0,0,0)
DispatchPointer(0,0,1,600,1200,0,0,0,0,0,0,0)
#等待1秒
UserWait(1000)
#点击 + 号
DispatchPress(KEYCODE_PLUS)
UserWait(1000)
#点击 9
DispatchPress(KEYCODE_9)
UserWait(1000);
#点击 =
Tap(600,1600)
UserWait(1000)
#翻转屏幕 参数0123分别代表0,90,180,270
#第二个参数 0表示旋转后恢复,非0则表示固定不变
RotateScreen(2,1)
UserWait(500)
脚本需要运行在手机上,所以先上传到手机上1
adb push monkey.script /sdcard/monkey.script
执行脚本1
adb shell monkey -f /sdcard/monkey.script -v -v 1
执行效果如下图:
Monkey Server
Monkey Server可以让我们从电脑端直接通过命令操控手机。Monkey Server在官方文档中没有介绍,不过源码中有示例,源码示例可以在这里查看README.NETWORK.txt
- 启动Monkey Server
adb shell monkey --port 1080 &
- PC端1080端口数据转发到客户端的1080端口
adb forward tcp:1080 tcp:1080
- 连接Monkey Server并进入控制台
telnet 127.0.0.1 1080
,在这里面输入Monkey Server的命令就可以操控手机了。
Monkey Server的常用命令:
- key [down|up] keycode – 指定Keycode的按键事件(分按下、弹起)
- touch [down|up|move] x y – 指定坐标的触屏操作(分按下、弹起、移动)
- trackball dx dy – 轨迹球操作
- tap x y – 指定坐标的触屏操作
- flip [open|close] – 调用软键盘
- wake – 唤醒设备
- press keycode – 指定Keycode的按键事件
- listvar – 列出所有的系统变量
- getvar varname – 获取给定系统变量值
- quit – 退出当前连接,且不接受新的连接
- done – 退出当前连接,但可以接受新的连接
- type – 输入字符
命令执行成功之后会返回OK,注意操作退出telnet前,需要执行done指令,否则再次连接,会报端口已占用的错误。只能重启设备以释放端口。
一个一个的输入命令来控制手机太麻烦,没人愿意使用。Monkey Server也是可以编写脚本,Linux中可以直接编写shell脚本即可,Window中可以借助wscript.shell
来完成
定义一个名为monkey_server_run.vbs的文件来写脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14set sh=WScript.CreateObject("WScript.Shell")
WScript.Sleep 2000
sh.SendKeys "open 127.0.0.1 1080 {ENTER}"
WScript.Sleep 2000
sh.SendKeys "press KEYCODE_6 {ENTER}"
WScript.Sleep 2000
sh.SendKeys "press KEYCODE_NUMPAD_ADD {ENTER}"
WScript.Sleep 2000
sh.SendKeys "press KEYCODE_9 {ENTER}"
WScript.Sleep 2000
sh.SendKeys "press KEYCODE_NUMPAD_EQUALS {ENTER}"
WScript.Sleep 2000
sh.SendKeys "done {ENTER}"
WScript.Sleep 1000
注意:这里有个问题,每次执行sh.SendKeys后面的指令的时候,指令中间的空格都会莫名的消失导致执行失败,试了一些办法之后也没成功,由于Monkey Server的用途也不是很大,前面的Monkey 脚本完全可以完成,后面还有更加强大的MonkeyRunner,遂放弃。
还需要先提前启动应用,所以使用一个bat批处理来完成下面的一些命令。定义一个文件名为monkey_server.bat1
2
3
4
5
6
7adb forward tcp:1080 tcp:1080
adb shell am start -n com.android.calculator2/com.android.calculator2.Calculator
start telnet.exe
cscript //nologo .\monkey_server_run.vbs
写完之后双击monkey_server.bat即可运行。
MonkeyRunner
MonkeyRunner也是Android SDK中自带的一个黑盒测试工具,支持Pyhon和Java,可以实现Monkey无法实现的一些逻辑控制。
先说说这俩后啥区别呢?
- Monkey是运行在设备上的,可以脱离PC,MonkeyRunner运行在PC上,往手机或模拟器上发送指令来测试。
- Monkey一般用来做一些随机性的测试,前面文章也写了,官方文档上就写了随机测试怎么用,至于编写自定义脚本还需要自己看源码,还是简单的脚本。MonkeyRunner支持条件判断,可以写出更强大的自定义测试脚本。
- MonkeyRunner可以同时运行多个测试设备,还可以将运行结果截图并跟已知的一个正确的截图做比较。
开始
想要运行MonkeyRunner的程序,首先要打开MonkeyRunner的控制界面,无论是官网还是网上的大部分文章说的打开方式都是双击打开sdk/tools/monkeyrunner.bat。不过我的sdk中却没有,后来在sdk/tools/bin/monkeyrunner.bat找到了它,可惜双击没反应,在cmd窗口中进入到当前文件夹执行monkeyrunner
命令报错1
2SWT folder '..\framework\x86_64' does not exist.
Please set ANDROID_SWT to point to the folder containing swt.jar for your platform.
我是不是下了个假的sdk?后来通过网上这篇文章解决了大部分问题,因为用了文章中的方法后还是会报一个错误..\framework\adb.exe": CreateProcess error=2, 系统找不到指定的文件
搜索了一下adb.exe在\sdk\platform-tools
目录中,拷贝过来之后运行成功。
MonkeyRunner包括三大模块:
- MonkeyRunner: 提供了将monkeyrunner程序连接到模拟器或者手机设备的方法。还提供了monkeyrunner程序创建界面和显示内置帮助的方法
- MonkeyDevice: 提供了安装卸载软件,启动 Activity以及向设备发送按键或者轻触事件。
- MonkeyImage:提供了截屏,将位图转换为各种格式,比较两个MonkeyImage对象和将图片写入文件的方法。
这三个模块都有啥方法可以供我们调用呢,官网有详细方法列表和解说:MonkeyRunner的,MonkeyDevice的,MonkeyImage的
使用MonkeyRunner的时候monkeyrunner 工具不会自动导入这些模块。要导入模块使用下面的命令1
from com.android.monkeyrunner import <module>
其中
简单小例子:进入monkeyrunner的命令行中输入下面的指令,可以看到如何操作一台设备1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#导入MonkeyRunner和MonkeyDevice两个模块
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
#连接当前设备并返回一个MonkeyDevice对象
device = MonkeyRunner.waitForConnection()
#安装一个应用,返回值是Boolean类型,可以根据返回值判断安装结果
device.installPackage('app-debug.apk')
#定义一个package变量
package="com.chs.androiddailytext"
#定义一个activity变量
activity="com.chs.androiddailytext.MainActivity"
#拼接成要启动的组件的名称
runComponent=package + '/' + activity
#启动组件
device.startActivity(component=runComponent)
#截屏
image=device.takeSnapshot()
#保存截屏的图片
image.writeToFile('111.png','png')
#按下菜单键
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
MonkeyRunner的录制回放工具
MonkeyRunner的录制回放工具用起来很方便,手动操作界面就可以自动生成执行脚本。不过不知道为啥官网并没有介绍这俩的用法,需要到源码中去把脚本拷贝过来自行查看:点击查源码,将源码中的monkey_recorder.py和monkey_playback.py两个文件拷贝到monkeyrunner.bat的同级目录下。
- Monkey_recorder 录制工具
- Monkey_playback 回放工具
可以看到这俩文件都是python文件,所以电脑上需要安装python的环境,具体安装方法可以去python官网下载安装
使用Monkey_recorder录制
双击monkey_recorder.py文件就可以启动录制工具了如下图
在上图的手机界面投影中,点击相应地方,它就会自动生成该位置的点击事件的脚本,头部有好几个菜单,这些菜单也能图形化的来设置不同的事件
- Wait : 用来在多个操作之间设置停顿,单位是秒。一般都会设置,因为自动化执行太快,而且电脑控制手机,之间还会有些延迟,可能PC这边执行完5个指令了,手机端才执行第二个动作。
- Press Button:模拟设备上的常用按键操作MENU,HOME,SEARCH,BACK
- TypeSoming:录入一个字符串,用来模拟输出
- Fling:模拟一个滑动操作,可以选择滑动方向,滑动时长,滑动步数
- Export Actions:将之前的操作生成的脚本代码保存到一个文件中,文件后缀名一般为
.mr
- Refresh Display:刷新界面
下面我们随便点击应用中的一些位置,生成的脚本保存如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18TOUCH|{'x':924,'y':1180,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':465,'y':888,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':148,'y':752,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':560,'y':1708,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':911,'y':1684,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':182,'y':1704,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':243,'y':1856,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':104,'y':528,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
TOUCH|{'x':1366,'y':1848,'type':'downAndUp',}
WAIT|{'seconds':2.0,}
注意:如果我们没有点击Wait按钮添加延时,它是不会自己添加延时的,上面代码中的延时操作都是自己打开文件添加的,如果不添加延时PC这边的指令可能嗖的一下就执行完了,而手机那边可能刚执行了两个就完了,剩下的执行也接收不到了。
使用monkey_playback.py播放
上面的文件生成了,下面开始播放,到monkeyrunner.bat所在目录下执行下面命令。如果不想每次都要该文件夹下执行monkeyrunner的命令可以配置一下环境变量。
1 | monkeyrunner %ANDROID_HOME%\tools\bin\monkey_playback.py F:\test\recorder.mr |
recorder.mr需要写绝对路径,相对路径运行不成功,另外运行monkey_playback的时候需要把monkey_recorder停掉否则没效果。我就是一开始没停掉结果运行回放没反应,就是不动也没日志,找了好久晕。
前面的操作方法基本上都是是基于touch事件的,touch事件是依赖于屏幕的坐标值的,而Android手机的碎片化导致有N多种屏幕分辨率的手机。导致从一个手机上生成的脚本在别的手机上运行部正确,无法复用脚本。想要更好的重用的话,可以使用界面上控件的id来做测试。
使用控件的id来做测试,需要用到EasyMonkeyDevice和By这两个类,这哥俩的用法很网也没有介绍,只能去源码中查看点击查看源码。不过使用它的话需要测试的手机设备能打开view server。一般情况下只有Android开发版手机 、模拟器、root后的手机才能打开view server。我尝试了下模拟器没有成功打开view server就放弃了,毕竟官方也没推荐使用。后面有更好用的UI Automator、Espresso等工具。