Android自动化测试入门(一)Monkey和MonkeyRunner

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 查看sdk
  • android 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来启动,命令格式

adb shell monkey [option] 

各种参数的作用官网上有详细文档: 官网地址

下面进入adb shell中做一个小例子:

通过 pm list packages 命令可以看到手机中所有的包名,可以随便找一个测试,这里使用系统计算器来测试它的包名是 com.android.calculator2

可以执行下面的命令,来执随机行应用1000次

monkey -p com.android.calculator2 1000

可以通过-v 来输出执行日志,比如

monkey -p com.android.calculator2 -v -v 100

-v的个数表示日志输出的级别,最多三个,越多日志越详细来看看输出的日志

data="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源码中的数值常量。

public 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 命令将运行日志导出来查看更详细的信息

//6.0及以下设备
adb bugreport > bugreport.txt
//7.0及以上设备
adb bugreport bugreport.zip

Monkey 脚本

有时候我们不想让它随机执行,通过脚本可以让测试按照我们自定义的流程来执行。使用-f参数就可以执行Monkey的脚本了 adb shell monkey -f 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.script

type= 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)

脚本需要运行在手机上,所以先上传到手机上

adb push monkey.script /sdcard/monkey.script

执行脚本

adb shell monkey -f /sdcard/monkey.script -v -v 1

执行效果如下图:

Monkey Server

Monkey Server可以让我们从电脑端直接通过命令操控手机。Monkey Server在官方文档中没有介绍,不过源码中有示例,源码示例可以在这里查看 README.NETWORK.txt

adb shell monkey --port 1080 &
adb forward tcp:1080 tcp:1080
telnet 127.0.0.1 1080

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的文件来写脚本

set 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.bat

adb 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 命令报错

SWT 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 工具不会自动导入这些模块。要导入模块使用下面的命令

from com.android.monkeyrunner import 

其中

是要导入的类名称。我们可以在同一个 from 语句中导入多个模块,只需用英文逗号分隔各模块名称即可。

简单小例子:进入monkeyrunner的命令行中输入下面的指令,可以看到如何操作一台设备

#导入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文件就可以启动录制工具了如下图

在上图的手机界面投影中,点击相应地方,它就会自动生成该位置的点击事件的脚本,头部有好几个菜单,这些菜单也能图形化的来设置不同的事件

.mr

下面我们随便点击应用中的一些位置,生成的脚本保存如下

TOUCH|{'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的命令可以配置一下环境变量。

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等工具。