Android自动化测试工具——Monkey
Android自动化测试工具——Monkey
上一周的软件测试课刚刚练习过移动应用的测试,通过Android SDK中的uiautomatorviewer(一个由Android提供的、用来扫描和分析Android应用程序的UI组件的GUI工具)来获取界面中的一个元素,然后通过点击按钮,读取、修改文本等来模拟真实用户和应用之间的交互。今天来说说另一个工界和学界中常用的Android测试工具——Monkey
Monkey简介
Monkey测试是Android平台下自动化测试的一种快速有效的手段,可运行在模拟器和实体设备上。通过Monkey工具可以模拟用户触摸屏幕、滑动轨迹球、按键等操作来对模拟器或者手机设备上的软件进行压力测试,检测该软件的稳定性、健壮性。它的原理是向系统发送伪随机的用户事件流(如按键输入、触摸输入、手势输入等),实现对正在开发的应用程序进行压力测试。因为这个工具在App中乱按、乱摸、乱滚、乱跳,像一个调皮的猴子,所以被称为Monkey。
Monkey工具的特点
- 1.测试对象为程序包,有一定局限性
- 2.使用的事件流数据流是随机的,不能自定义
- 3.可对事件数量、类型、频率设置
补充:MonkeyRunner官方文档的网址
http://developer.android.com/guide/developing/tools/monkeyrunner_concepts.html
Monkey的基本语法
参数名 | 基本功能 |
---|---|
-p | 参数-p用于约束限制,用此参数指定一个或多个包(Package,即App)。指定包之后,Monkey将只允许系统启动指定的App。如果不指定包,Monkey将允许系统启动设备中的所有APP。 |
-v | 用于指定反馈信息级别(信息级别就是日志的详细程度),总共分3个级别:level0-2 |
-s <\seed> | 用于指定伪随机数生成器的seed值,如果seed相同,则两次Monkey测试产生的时间序列也相同。 |
-throttle <毫秒> | 用于指定用户操作(即事件)间的时延,单位是毫秒 |
–ignore-crashes | 用于指定当应用程序奔溃时(Force & Close错误),Monkey是否停止运行。如果使用此参数,即使应用程序奔溃,Monkey依然会发送事件,直到事件计数完成。 |
–ignore-timeouts | 用于指定当前应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行,如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成。 |
–ignore-security-exceptions | 用于指定当程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行。如果使用此参数,即使应用程序发送许可错误,Monkey依然会发送事件,直到事件计数完成 |
–kill-process-after-error | 用于指定应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程)。 |
–monitor-native-crashes | 用于指定是否监视并报告应用程序发生崩溃的本地代码 |
–pct- {+事件类别} {+事件类别百分比} | 用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数据占总事件数目的百分比) |
–pct-touch {+百分比} | 调整触摸时间的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某个单一位置) |
–pct-motion | 调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随机事件和一个up事件组成) |
–pct-trackball {+百分比 } | 调整轨迹事件的百分比(轨迹事件由一个或者几个随机的移动组成,有时还伴随有点击) |
–pct-nav | 调整“基本”导航事件的百分比(导航事件由来自方向输入设备up/down/left/right组成) |
–pct-majornav {+百分比} | 调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键) |
–pct-syskeys {+百分比} | 调整“系统”按键事件的百分比(这些按键通常被保留,由系统使用,如Home、Back、Start Call、End Call及音量 |
–pct-appswitch {+百分比} | 调整启动Activity的百分比。在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity |
–pct-anyevent {+百分比} | 调整其它类型事件的百分比。它包罗了所有其它类型的事件,如:按键、其它不正常的设备按钮,等等 |
–wait-dbg | 停止执行中的Monkey,直到有调试器和它相连接。 |
(!!!注:这里由于博客编辑器的原因,“-s ”的参数seed前面加了一个“\”,正常情况下没有这个符号。)
Monkey测试示例图解
我选择的app是开源中国(上周测试考试用到的apk)
(1)将apk安装到模拟器中。安装后,能够在模拟器中看到安装好的apk,如下图:
(2)安装好apk文件后,需要知道应用程序主Activity(第一个启动的Activity)所在的包名。
获取包名有多种方法,可以参照这个网址中提到的指令。
http://www.51testing.com/html/93/136593-3714533.html
这里得到的包名如下图:
(3) 使用moneky命令进行自动化压力测试。
命令为:
#monkey -p net.oschina.app.improve -v 100
//(参数说明:-p后跟软件所在包名,-v后跟测试的次数)。这里对该软件发送了100次的伪随机事件,即进行了100次的自动化测试。
(4) 查看测试的结果。
我的测试结果如下图:
如果测试没有通过,会报错。如果输出了“Monkey Finished”则说明测试通过,这里的测试通过。
但是查看结果还是有不明白的地方,如Event Percentages的0-10各代表什么?
这一点,我们可以查看android-4.2.2_r1.2中的MonkeySourceRandom.java中定义的这些值:
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_NAV = 5;
public static final int FACTOR_MAJORNAV = 6;
public static final int FACTOR_SYSOPS = 7;
public static final int FACTOR_APPSWITCH = 8;
public static final int FACTOR_FLIP = 9;
public static final int FACTOR_ANYTHING = 10;
public static final int FACTORZ_COUNT = 11; // should be last+1
private static final int GESTURE_TAP = 0;
private static final int GESTURE_DRAG = 1;
private static final int GESTURE_PINCH_OR_ZOOM = 2;
然后再来看Monkey.java源码中的processOptions()方法
private boolean processOptions() {
// quick (throwaway) check for unadorned command
if (mArgs.length < 1) {
showUsage();
return false;
}
try {
String opt;
while ((opt = nextOption()) != null) {
if (opt.equals("-s")) {
mSeed = nextOptionLong("Seed");
} else if (opt.equals("-p")) {
mValidPackages.add(nextOptionData());
} else if (opt.equals("-c")) {
mMainCategories.add(nextOptionData());
} else if (opt.equals("-v")) {
mVerbose += 1;
} else if (opt.equals("--ignore-crashes")) {
mIgnoreCrashes = true;
} else if (opt.equals("--ignore-timeouts")) {
mIgnoreTimeouts = true;
} else if (opt.equals("--ignore-security-exceptions")) {
mIgnoreSecurityExceptions = true;
} else if (opt.equals("--monitor-native-crashes")) {
mMonitorNativeCrashes = true;
} else if (opt.equals("--ignore-native-crashes")) {
mIgnoreNativeCrashes = true;
} else if (opt.equals("--kill-process-after-error")) {
mKillProcessAfterError = true;
} else if (opt.equals("--hprof")) {
mGenerateHprof = true;
} else if (opt.equals("--pct-touch")) {
int i = MonkeySourceRandom.FACTOR_TOUCH;
mFactors[i] = -nextOptionLong("touch events percentage");
} else if (opt.equals("--pct-motion")) {
int i = MonkeySourceRandom.FACTOR_MOTION;
mFactors[i] = -nextOptionLong("motion events percentage");
} else if (opt.equals("--pct-trackball")) {
int i = MonkeySourceRandom.FACTOR_TRACKBALL;
mFactors[i] = -nextOptionLong("trackball events percentage");
} else if (opt.equals("--pct-rotation")) {
int i = MonkeySourceRandom.FACTOR_ROTATION;
mFactors[i] = -nextOptionLong("screen rotation events percentage");
} else if (opt.equals("--pct-syskeys")) {
int i = MonkeySourceRandom.FACTOR_SYSOPS;
mFactors[i] = -nextOptionLong("system (key) operations percentage");
} else if (opt.equals("--pct-nav")) {
int i = MonkeySourceRandom.FACTOR_NAV;
mFactors[i] = -nextOptionLong("nav events percentage");
} else if (opt.equals("--pct-majornav")) {
int i = MonkeySourceRandom.FACTOR_MAJORNAV;
mFactors[i] = -nextOptionLong("major nav events percentage");
} else if (opt.equals("--pct-appswitch")) {
int i = MonkeySourceRandom.FACTOR_APPSWITCH;
mFactors[i] = -nextOptionLong("app switch events percentage");
} else if (opt.equals("--pct-flip")) {
int i = MonkeySourceRandom.FACTOR_FLIP;
mFactors[i] = -nextOptionLong("keyboard flip percentage");
} else if (opt.equals("--pct-anyevent")) {
int i = MonkeySourceRandom.FACTOR_ANYTHING;
mFactors[i] = -nextOptionLong("any events percentage");
} else if (opt.equals("--pct-pinchzoom")) {
int i = MonkeySourceRandom.FACTOR_PINCHZOOM;
mFactors[i] = -nextOptionLong("pinch zoom events percentage");
} else if (opt.equals("--pkg-blacklist-file")) {
mPkgBlacklistFile = nextOptionData();
} else if (opt.equals("--pkg-whitelist-file")) {
mPkgWhitelistFile = nextOptionData();
} else if (opt.equals("--throttle")) {
mThrottle = nextOptionLong("delay (in milliseconds) to wait between events");
} else if (opt.equals("--randomize-throttle")) {
mRandomizeThrottle = true;
} else if (opt.equals("--wait-dbg")) {
// do nothing - it's caught at the very start of run()
} else if (opt.equals("--dbg-no-events")) {
mSendNoEvents = true;
} else if (opt.equals("--port")) {
mServerPort = (int) nextOptionLong("Server port to listen on for commands");
} else if (opt.equals("--setup")) {
mSetupFileName = nextOptionData();
} else if (opt.equals("-f")) {
mScriptFileNames.add(nextOptionData());
} else if (opt.equals("--profile-wait")) {
mProfileWaitTime = nextOptionLong("Profile delay" +
" (in milliseconds) to wait between user action");
} else if (opt.equals("--device-sleep-time")) {
mDeviceSleepTime = nextOptionLong("Device sleep time" +
"(in milliseconds)");
} else if (opt.equals("--randomize-script")) {
mRandomizeScript = true;
} else if (opt.equals("--script-log")) {
mScriptLog = true;
} else if (opt.equals("--bugreport")) {
mRequestBugreport = true;
} else if (opt.equals("--periodic-bugreport")){
mGetPeriodicBugreport = true;
mBugreportFrequency = nextOptionLong("Number of iterations");
} else if (opt.equals("-h")) {
showUsage();
return false;
} else {
System.err.println("** Error: Unknown option: " + opt);
showUsage();
return false;
}
}
} catch (RuntimeException ex) {
System.err.println("** Error: " + ex.toString());
showUsage();
return false;
}
// If a server port hasn't been specified, we need to specify
// a count
if (mServerPort == -1) {
String countStr = nextArg();
if (countStr == null) {
System.err.println("** Error: Count not specified");
showUsage();
return false;
}
try {
mCount = Integer.parseInt(countStr);
} catch (NumberFormatException e) {
System.err.println("** Error: Count is not a number");
showUsage();
return false;
}
}
return true;
}
所以,Monkey运行结果中对应的就应该是:
数字 | 对应量 | 解释 |
---|---|---|
0 | –pct-touch//touch events percentage | 触摸事件百分比(触摸事件是一个在屏幕单一位置的按下-抬起事件) |
1 | –pct-motion//motion events percentage | 手势事件百分比(手势事件是由一个在屏幕某处的按下事件、一系列的伪随机移动、一个抬起事件组成)即一个滑动操作,但是是直线的,不能拐弯 |
2 | –pct-pinchzoom//pinch zoom events percentage | 二指缩放百分比,即智能机上的放大缩小手势操作 |
3 | –pct-trackball//trackball events percentage | 轨迹球事件百分比(轨迹球事件包括一个或多个随机移动,有时还伴有点击。轨迹球现在智能手机上已经没有了,就是类似手柄的方向键一样) |
4 | –pct-rotation//screen rotation events percentage | 屏幕旋转百分比,横屏竖屏 |
5 | –pct-nav//nav events percentage | “基本”导航事件百分比(导航事件包括上下左右,如方向输入设备的输入)老手机的上下左右键,智能机上没有 |
6 | –pct-majornav//major nav events percentage | “主要”导航事件百分比(这些导航事件通常会引发UI的事件,例如5-way pad的中间键、回退键、菜单键) |
7 | –pct-syskeys//system(key) operations percentage | “系统”按钮事件百分比(这些按钮一般专供系统使用,如Home, Back, Start Call, End Call,音量控制) |
8 | –pct-appswitch//app switch events percentage | 启动activity事件百分比。在随机的间隔里,Monkey会执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法 |
9 | –pct-flip//keyboard flip percentage | 键盘轻弹百分比,如点击输入框,键盘弹起,点击输入框以外区域,键盘收回 |
10 | –pct-anyevent//anyevents percentage | 其他类型事件百分比。包括了其他所有的类型事件,如按键、其他不常用的设备上的按钮等等。 |
至此,monkey运行结果的查看结束。
上一篇: Java使用百度人脸识别API攻略
下一篇: nginx搭建反向代理
推荐阅读
-
Android 自动化测试经验分享 深入UiScrollable
-
Android 自动化测试经验分享 UiObejct.getFromParent()的使用方法
-
android monkey自动化测试改为java调用monkeyrunner Api
-
android自动化测试知识点总结
-
Android 自动化测试经验分享 深入UiScrollable
-
自动化测试工具开发用什么语言(页面自动化测试工具使用)
-
Android 自动化测试经验分享 UiObejct.getFromParent()的使用方法
-
自动化测试工具开发用什么语言(页面自动化测试工具使用)
-
软件测试常用的测试工具有哪些(selenium自动化测试实战)
-
软件测试常用的测试工具有哪些(selenium自动化测试实战)