MonkeyRunner
1)简介:Android SDK中自带的一个黑盒测试工具,在PC端通过Android API控制设备的运行。支持Python脚本,相对Monkey而言可以增加逻辑控制。
2)组成模块:①MonkeyRunner ②MonkeyDevice ③MonkeyImage
3)官方文档地址:https://developer.android.com/studio/test/monkeyrunner/index.html
4)启动MonkeyRunner,需要先切换到sdk/tools/bin目录下(环境变量我已经进行了配置但是。。。之后找找原因),执行./monkeyrunner。
5)MonkeyRunner模块方法
①alert 对话框交互
②choice 对话框交互
③ help 命令查询
④ input 对话框交互
⑤ sleep 终端,单位秒
⑥ waitForConnection 和设备建立通讯,返回MonkeyDevice
6)MonkeyDevice模块方法
① broadcastIntent 发送广播,不太常用
②drag 拖放操作
③ getProperty 获取系统变量值
④ getSystemProperty 和abd shell getprop<key>作用一样,获取系统调试的系统变量
⑤ installPackage 安装应用
⑥ instrument 执行单元测试的方法
⑦ press 发送按键操作
⑧ reboot 重启设备
⑨ removePackage 卸载Apk
⑩ shell 和adb shell作用一样
- startActivity 启动应用
- takeSnapshot 从设备上截图,生成MonkeyImage对象
- touch 一个单机的手势操作
- type 把一组字符串逐个发送到设备上
- wake 唤醒屏幕
7)MonkeyImage模块方法
① convertToBytes将图像转换成字节码
② getRawPixel 获取指定坐标的像素点,返回tuple类型
③ getRawPixelInt 获取指定坐标的像素点,返回整型
④ getSubImage 获取子图像
⑤ sameAs 对两个MonkeyImage对象进行比较
⑥ writeToFile 将图像写到文件中,生成一个图像
8)退出MonkeyRunner,control+d。
9)录制回放工具使用[运行工具时报错,之后再把这段补上]
①monkey_recorder.py和monkey_playback.py文件获取,放入sdk/tools目录下地址。
②直接运行monkey_recorder.py,打开录制工具。
③功能按钮:Wait生成一条等待的指令、Press a Button执行物理按键 、Type Something 输入字符、Fling手势操作、Export Action导出录制记录、Refresh Display
10)EasyMonkeyDevice模块
简介:通过识别对象的id,来实现对控件的操作
①touch
②type
③locate 返回控件的位置
④exists 控件是否存在
⑤visible 控件是否可见
⑥getText 获取控件文本属性
⑦getFocusedWindowId 获取当前界面窗口的id
11)By模块
指向一个id xx的控件
12)HierarchyViewer模块
①MonkeyDevice.getHierarchyViewer()//获得一个HierarchyViewer对象
②setupViewServer
③findViewById(String id, ViewNode rootNode)//返回根据id节点查找到的视图
④getFocusedWindowName//获取当前接收焦点的窗口。
⑤getAbsolutePositionOfView(ViewNode node) //获取视图节点的绝对x / y位置
⑥getAbsoluteCenterOfView(ViewNode node) //获取指定视图节点的绝对x / y中心。
⑦visible(ViewNode node)
⑧getText(ViewNode node)
//启动
./monkeyrunner
//引入模块
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage
//MonkeyRunner 5个
>>> MonkeyRunner.alert("MonkeyRunner alert","imooc","OK")
>>> MonkeyRunner.choice("MonkeyRunner choice",["test1","test2"],"imooc")
>>> MonkeyRunner.input("MonkeyRunner input","Hi~","imooc","OK","Cancel")
>>> MonkeyRunner.sleep(4)
>>> MonkeyRunner.waitForConnection(10,'enument-5554')//不做参数输入时,默认连接ADB已经连接的设备,第一个参数是连接超时时间,第二是设备名称
//MonkeDevice
>>> device.installPackage("apk包的绝对路径")
True
>>> device.shell("pm list package |grep note")//获取包名,没有整明白
>>> package="com.android.calculator2"//启动计算器
>>> removePackage(包名)
>>> activity="com.android.calculator2.Calculator"
>>> runComponent=package+"/"+activity
>>> device.startActivity(component=runComponent)
>>> device.press("KEYCODE_7",MonkeyDevice.DOWN_AND_UP)//输入7
>>> device.type("+")//输入+
>>> device.touch(800,1100,MonkeyDevice.DOWN_AND_UP)//输入9
>>> device.getProperty("display.width")//获取屏幕的宽
//MonkeyImage
>>> image=device.takeSnapshot()
>>> subimage=image.getSubImage((100,1100,190,196))
>>> subimage.writeToFile("/Users/yuanyi/Downloads/subimage.png","png")
True
>>> image.getRawPixel(100,100)
(-1, 255, 255, 255)
>>> subimage.sameAs(subimage2,0.9)//第二参数是相似度
False
//启动view server(已经忘记具体是干嘛的了)
adb shell service call window 1 i32 4939
Result: Parcel(00000000 00000000 '........')
adb shell service call window 3
Result: Parcel(00000000 00000001 '........')
//操作计算器python脚本
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage
from com.android.monkeyrunner.easy import EasyMonkeyDevice,By
device = MonkeyRunner.waitForConnection()
device.startActivity('com.android.calculator2/.Calculator')
easy = EasyMonkeyDevice(device)
print'****case01 user MonkeyDevice and MonkeyImage check claculator result****'
print'---calculator 3*8 with press Method'
MonkeyRunner.sleep(1)
device.press('KEYCODE_3',MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
device.press('KEYCODE_NUMPAD_MULTIPLY',MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
device.press('KEYCODE_8',MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(3)
image01=device.takeSnapshot()
subimage01=image01.getSubImage(easy.locate(By.id(''id/result'')))
//计算后需要清理输入框内容,我没有贴这部分内容
print'---calculator 4*6 with touch Method'
//涉及到想xy值得地方需要根据实际设备重新计算
device.touch(50,1100,MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
device.touch(900,1200,MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
device.touch(600,1100,MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(3)
image02=device.takeSnapshot()
subimage02=image02.getSubImage(easy.locate(By.id(''id/result'')))
if(subimage01.sameAs(subimage02,1)):
print'[pass] The result of 3*8 and 4*6 is equal!'
else:
print'[fail] The result of 3*8 and 4*6 is not equal!'
print'****case02 user EasyMonkeyDevice check claculator result****'
easy.touch(By.id('id/digit_5'),MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
easy.touch(By.id('id/op_mul'),MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
easy.touch(By.id('id/digit_7'),MonkeyDevice.DOWN_AND_UP)
MonkeyRunner.sleep(1)
str=easy.getText(By.id('id/result'))
if(str=='35'):
print'[pass] The result of 3*7 is correct!'
else:
print'[fail] The result of 3*7 is not correct!'
device.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
遇到的问题
1)windows电脑下提示SWT folder '..\framework\x86_64' does not exist.
Please set ANDROID_SWT to point to the folder containing swt.jar for your platfo
rm.
解决方法:
①打开monkeyrunner.bat文件
②找到if exist %frameworkdir%\%jarfile% goto JarFileOk
set frameworkdir=lib
③将lib修改成..\lib,swt.jar所在的文件夹。
④在tools下面新建一个framework文件夹,把adb.exe(platform-tools目录下)拷贝过去。
网上找到的解决方法还不了解原理,希望自己之后能自己解决这种问题。
2)在x86的模拟器上按照慕课网的app提示失败
原因:慕课网app使用的是arm原生library,需要安装arm类型的模拟器,比较主流的是genymotion。
区别:x86架构采用CISC,ARM采用RISC。CISC(复杂指令集计算机)和RISC(精简指令集计算机)是CPU的两种架构。它们的区别在于不同的CPU设计理念和方法
3)无法定位相同/无id控件
解决方法:
①使用HierarchyViewer模块
//根据父节点对应子节点的视图对象
def getChildView(parentId, *childSeq)://*childSeq可变参数
hierarchyViewer = device.getHierarchyViewer()
childView="hierarchyViewer.findViewById('" + parentId +"')"
for index in childSeq:
childView += ('.children[' + str(index) + ']')
return eval(childView)//eval() 函数用来执行一个字符串表达式,并返回表达式的值。
//获取视图对象中心点坐标
def getBtnPoint(btn):
point = device.getHierarchyViewer().getAbsoluteCenterOfView(btn);
return point
//实际调用
askView = getChildView('id/tabs',1)
askPpoint = getBtnPoint(askView)
device.touch(askPpoint.x,askPpoint.y,MonkeyDevice.DOWN_AND_UP)