一、Monkeyrunner工具提供了一些API,使用此API写出的程序可以在Android代码之外控制Android设备和模拟器。

通过 Monkeyrunner,您可以写出一个Python程序去安装一个Android应用程序或测试包,运行它,向它发送模拟击键,截取它的用户界面图片,并将截图存储于工作站上。Monkeyrunner工具的主要设计目的是用于测试功能/框架水平上的应用程序和设备,或用于运行单元测试套件,但您当然也可以将其用于其它目的。

二、monkeyrunner工具同Monkey工具的差别

Monkey:
Monkey工具直接运行在设备或模拟器的adb shell中,生成用户或系统的伪随机事件流。
Monkey运行在设备内的环境中。

monkeyrunner:
monkeyrunner工具则是在工作站上通过API定义的特定命令和事件控制设备或模拟器。
Monkeyrunner运行在工作站上。

三、monkeyrunner的测试类型
1、多设备控制:monkeyrunner API可以跨多个设备或模拟器实施测试套件。您可以在同一时间接上所有的设备或一次启动全部模拟器(或统统一起),依据程序依次连接到每一个,然后运行一个或多个测试。您也可以用程序启动一个配置好的模拟器,运行一个或多个测试,然后关闭模拟器。
2、 功能测试: monkeyrunner可以为一个应用自动贯彻一次功能测试。您提供按键或触摸事件的输入数值,然后观察输出结果的截屏。
3、 回归测试:monkeyrunner可以运行某个应用,并将其结果截屏与既定已知正确的结果截屏相比较,以此测试应用的稳定性。
4、 可扩展的自动化:由于monkeyrunner是一个API工具包,您可以基于Python模块和程序开发一整套系统,以此来控制Android设备。除了使用monkeyrunner API之外,您还可以使用标准的Python os和subprocess模块来调用Android Debug Bridge这样的Android工具。

四、运行monkeyrunner
您可以直接使用一个代码文件运行monkeyrunner,抑或在交互式对话中输入monkeyrunner语句。不论使用哪种方式,您都需要调用 SDK目录的tools子目录下的monkeyrunner命令。如果您提供一个文件名作为运行参数,则monkeyrunner将视文件内容为 Python程序,并加以运行;否则,它将提供一个交互对话环境。

monkeyrunner的命令语法为:
monkeyrunner -plugin

五、例子:

下面例子是测试向联系人应用中添加一条联系人。
环境:手机语言环境设置为英文。
联系人列表为空。
即新启动联系人应用后,是如下屏幕。

 看代码:

# 代码文件:contacts.py

# 导入要用到的代码库

from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
from com.android.monkeyrunner import MonkeyImage
from com.android.monkeyrunner.easy import EasyMonkeyDevice
from com.android.monkeyrunner.easy import HierarchyViewer  // 经过我检查,这里的路径不对. 需要读者注意
from com.android.monkeyrunner.easy import By
from com.android.hierarchyviewerlib.device import ViewNode

#初始化 MonkeyDevice,device类型是MonkeyDevice

device = MonkeyRunner.waitForConnection()

#初始化EasyMonkeyDevice,easy_device的类型是EasyMonkeyDevice

#在android 2.3.3中,加入了新的API,即EasyMonkeyDevice
easy_device = EasyMonkeyDevice(device)

print 'start Contacts'

# 启动Contacts 应用

# 启动方法使用了adb shell中的am命令,关于am命令的使用,可以在启动adb shell后,键入am回车,里面有

# 该命令的帮助文档
device.shell('am start -a android.intent.action.MAIN -n com.android.contacts/.DialtactsContactsEntryActivity')

print 'press menu'
print 'check have any'

# shell 命令返回后,休眠两秒,等待contacts应用启动起来

MonkeyRunner.sleep(2)

# 如果联系人为空,就会出现"you don't have any..."的界面,其中显示文字的控件(TextView)的id为"emptyText"

# 这里我们检查一下,这个TextView控件是否可见,这个函数是EasyMonkeyDevice类提供的功能
text = easy_device.visible(By.id('id/emptyText'))    #这步操作耗时较长,因为按id查找控件需要时间较长
print text  #如果可见,将打印出True

# 通过MonkeyDevice获取HierarchyViewer对象实例

hierarchy_viewer = device.getHierarchyViewer()     

#通过HierarchyViewer获取ViewNode实例(一个viewnode实例代表一个控件)

view_node = hierarchy_viewer.findView('id/emptyText')

#获取控件内的文本
text = view_node.namedProperties.get('mText').toString()
if text.find('have any') < 0:
    print 'not find have any!'
else:
    print 'find have any!'

print text

# 获取当前屏幕的截图

new_img = device.takeSnapshot()

# 将截图保存到文件      
new_img.writeToFile('/home/lstest/test1.png', 'png')

# 下面代码实现按菜单进入新建联系人界面

print "menu" 
device.press('KEYCODE_MENU', 'DOWN_AND_UP')   
device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_RIGHT', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_RIGHT', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_CENTER', 'DOWN_AND_UP')

# 下面代码将光标移入First Name文本输入框

device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_UP', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_DOWN', 'DOWN_AND_UP')
device.type('ls_01')     # 输入联系人姓名 "ls_01"

MonkeyRunner.sleep(3)

#下面代码将光标移入Phone文本输入框
device.press('KEYCODE_DPAD_DOWN', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_DOWN', 'DOWN_AND_UP')
device.press('KEYCODE_DPAD_RIGHT', 'DOWN_AND_UP')

device.type('12345678901') #输入电话号码
easy_device.touch(By.id('id/btn_done'), 'DOWN_AND_UP') #实现点击“Done”按钮功能
MonkeyRunner.sleep(5)

#获取截图并保存 (截图如下:)

new_img = device.takeSnapshot()    
new_img.writeToFile('/home/lstest/test2.png', 'png')

#返回Idle界面

device.press('KEYCODE_BACK', 'DOWN_AND_UP')
device.press('KEYCODE_BACK', 'DOWN_AND_UP')

#文件结束

联系人建立后截图: