程序编写完成后进行测试一定是必不可少的,Android Sdk给我们提供了Monkey和Monkeyrunner这两个自动化测试工具。时光境迁,随着版本的不断更新迭代,Monkey和Monkeyrunner也在不断的改变,改变的速度甚至已经到了官方文档有时都跟不上了,这无疑给我们的学习带来很多困扰。
今天我把我近期使用Monkey和Monkeyrunner的一些体会与大家分享,Sdk版本为Rev22.01,Api17(4.22).
基本语法如下:
$ adb shell monkey [options] <event-count>
如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送500个伪随机事件:
$ adb shell monkey -p your.package.name -v 500
Windows下(注:2—4步是为了查看我们可以测试哪些应用程序包,可省略):
1、 通过eclipse启动一个Android的emulator
2、 在命令行中输入:adb devices查看设备连接情况
C:\Documents and Settings\Administrator>adb devices
List of devices attached
emulator-5554 device
3、 在有设备连接的前提下,在命令行中输入:adb shell 进入shell界面
C:\Documents and Settings\Administrator>adb shell
#
4、 查看data/data文件夹下的应用程序包。注:我们能测试的应用程序包都在这个目录下面
C:\Documents and Settings\Administrator>adb shell
如:
com.android.htmlviewer
com.android.settings
com.android.netspeed
com.android.providers.userdictionary
com.android.browser
com.android.contacts
com.android.alarmclock
等
5.在其中找到我们需要测试的包名com.marshalchen.MonkeyTest1
6、 以com.marshalchen.MonkeyTest1 作为对象进行MonkeyTest
#monkey -p com.marshalchen.MonkeyTest1 -v 500
其中-p表示对象包 –v 表示事件数量
运行过程中,Emulator中的应用程序在不断地切换画面。
按照选定的不同级别的反馈信息,在Monkey中还可以看到其执行过程报告和生成的事件。
如:Sending Pointer ACTION_DOWN x=35.0 y=259.0Monkey Test执行过程中在下列三种情况下会自动停止:
1、如果限定了Monkey运行在一个或几个特定的包上,那么它会监测试图转到其它包的操作,并对其进行阻止。
2、如果应用程序崩溃或接收到任何失控异常,Monkey将停止并报错。
3、如果应用程序产生了应用程序不响应(application not responding)的错误,Monkey将会停止并报错。
通过多次并且不同设定下的Monkey测试才算它是一个稳定性足够的程序。
您可以直接使用一个代码文件运行monkeyrunner,抑或在交互式对话中输入monkeyrunner语句。不论使用哪种方式,您都需要调用SDK目录的tools子目录下的monkeyrunner命令。如果您提供一个文件名作为运行参数,则monkeyrunner将视文件内容为Python程序,并加以运行;否则,它将提供一个交互对话环境。
monkeyrunner的命令语法为:
monkeyrunner -plugin
# 导入此程序所需的monkeyrunner模块
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
# 连接当前设备,返回一个MonkeyDevice对象
device = MonkeyRunner.waitForConnection()
# 安装Android包,注意,此方法返回的返回值为boolean,由此您可以判断安装过程是否正常
device.installPackage('myproject/bin/MyApplication.apk')
# 运行此应用中的一个活动device.startActivity(component='com.marshalchen.Monkeyrunner.MainActivity')
# 按下菜单按键
device.press('KEYCODE_MENU','DOWN_AND_UP')
# 截取屏幕截图
result = device.takeSnapShot
# 将截图保存至文件
result.writeToFile('myproject/shot1.png','png')
import sys
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
#connect device 连接设备
#第一个参数为等待连接设备时间
#第二个参数为具体连接的设备
device = mr.waitForConnection(1.0,'emulator-5554')
if not device:
print >> sys.stderr,"fail"
sys.exit(1)
#定义要启动的Activity
componentName='kg.monkey/.MonkeyActivity'
#启动特定的Activity
device.startActivity(component=componentName)
mr.sleep(3.0)
#do someting 进行我们的操作
#输入 a s d
device.type('asd')
#输入回车
device.press('KEYCODE_ENTER')
#return keyboard 点击返回用于取消等下看到截图的下方的白条
#device.press('KEYCODE_BACK')
#------
#takeSnapshot截图
mr.sleep(3.0)
result = device.takeSnapshot()
#save to file 保存到文件
result.writeToFile('takeSnapshot\\result1.png','png');
monkeyrunner monkey_recorder.py
#!/usr/bin/env monkeyrunner
# Copyright 2010, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner.recorder import MonkeyRecorder as recorder
device = mr.waitForConnection()
recorder.start(device)
#!/usr/bin/env monkeyrunner
# Copyright 2010, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from com.android.monkeyrunner import MonkeyRunner
# The format of the file we are parsing is very carfeully constructed.
# Each line corresponds to a single command. The line is split into 2
# parts with a | character. Text to the left of the pipe denotes
# which command to run. The text to the right of the pipe is a python
# dictionary (it can be evaled into existence) that specifies the
# arguments for the command. In most cases, this directly maps to the
# keyword argument dictionary that could be passed to the underlying
# command.
# Lookup table to map command strings to functions that implement that
# command.
CMD_MAP = {
'TOUCH': lambda dev, arg: dev.touch(**arg),
'DRAG': lambda dev, arg: dev.drag(**arg),
'PRESS': lambda dev, arg: dev.press(**arg),
'TYPE': lambda dev, arg: dev.type(**arg),
'WAIT': lambda dev, arg: MonkeyRunner.sleep(**arg)
}
# Process a single file for the specified device.
def process_file(fp, device):
for line in fp:
(cmd, rest) = line.split('|')
try:
# Parse the pydict
rest = eval(rest)
except:
print 'unable to parse options'
continue
if cmd not in CMD_MAP:
print 'unknown command: ' + cmd
continue
CMD_MAP[cmd](device, rest)
def main():
file = sys.argv[1]
fp = open(file, 'r')
device = MonkeyRunner.waitForConnection()
process_file(fp, device)
fp.close();
if __name__ == '__main__':
main()
.jar
文件,以此来扩展monkeyrunnerAPI。您可以使用您自己写的类或者继承现有的类来扩展monkeyrunnerAPI。您还可以使用此功能来初始化monkeyrunner环境。
-plugin
参数来调用monkeyrunner
命令。
com.android.monkeyrunner
包中的几个主要的monkeyrunner类:MonkeyDevice
, MonkeyImage
和MonkeyRunner.
请注意,插件无法让你访问Android的SDK。您不能导入com.android.app
等包。这是因为monkeyrunner是在框架API层次之下与设备或模拟器进行交互的。
.jar
文件可以指定一个类,使其在脚本执行之前就实例化。如欲指定这个类,您需要在.jar
文件的manifest中添加键MonkeyRunnerStartupRunner
。其值为启动时运行的类的名称。以下代码段显示了如何在一个ant
构建脚本达到这样的目的:
如欲访问monkeyrunner的运行时环境,启动类可以实现com.google.common.base.Predicate
。例如,用这个类在默认的命名空间中设置一些变量:
package com.android.example;
import com.google.common.base.Predicate;
import org.python.util.PythonInterpreter;
public class Main implements Predicate {
@Override
public boolean apply(PythonInterpreter anInterpreter) {
/*
* Examples of creating and initializing variables in the monkeyrunner environment's
* namespace. During execution, the monkeyrunner program can refer to the variables "newtest"
* and "use_emulator"
*
*/
anInterpreter.set("newtest", "enabled");
anInterpreter.set("use_emulator", 1);
return true;
}
}
1.“device.touch(10,100, 'DOWN_AND_UP')” 为什么报错?
ANS:可以把 'DOWN_AND_UP' 替换为 'MonkeyDevice.DOWN_AND_UP' ,这个问题的主要原因跟Monkeyrunner有关。
2.我输入了很多指令,但是很多没有执行
Ans:可以尝试 MonkeyRunner.sleep(time_in_seconds) 方法,让不同的动作之间有间隔。