移动测试基础 Android: 通过 cucumber 驱动 monkey 做稳定性测试

imzack · June 29, 2018 · Last by imzack replied at August 31, 2018 · Last modified by admin 恒温 · 2316 hits

主要内容

  • 稳定性测试是什么
  • Monkey介绍
  • 自动化Monkey

稳定性测试是什么

通过随机点击屏幕一段时间,看看app会不会奔溃,能不能维持正常运行。

Monkey介绍

Monkey是一个命令行工具,它可以运行在我们的模拟器或者设备当中。它可以发送一些伪随机(pseudo-random)的用户事件流,例如点击,触摸,手势等。我们能够使用Monkey工具来对我们所开发的应用进行压力测试。Monkey测试是一种为了测试软件的稳定性,健壮性的快速有效的方法。
Monkey 常用命令
基本语法如下:

adb shell monkey [options] <event-count>

如果什么参数都不给,monkey将以无反馈模式进行启动,并把事件任意发送到安装在目标环境下中的全部包。
下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送500个伪随机事件:

adb shell monkey -p your.package.name -v 500

根据Monkey 官网的介绍:https://developer.android.com/studio/test/monkey 可以添加对应的执行参数。
Monkey的参数都是根据具体需求设定的,主要分为常规类,事件类,约束类和调试类。下面就对这些命令进行说明:

类别 参数 说明
常规类 --help 显示moneky参数帮助信息usage
-v 打印日志信息,每个-v将增加反馈信息的级别。-v越多日志信息就会越详细,不过目前最多支持三个-v。Level0:一个-v,除启动提示、测试完成和最终结果之外,提供较少信息。Level1:两个-v,提供较为详细的测试信息,如逐个发送到Activity的事件。Level2:三个-v,提供更加详细的设置信息,如测试中被选中的或未被选中的Activity。
事件类 -s 伪随机数生成器的seed值。如果用相同的seed值再次运行 Monkey,它将生成相同的事件序列。
--throttle 后面接时间,单位为毫秒,表示事件之间的固定延时(即执行每一个指令的间隔时间),若不接这个选项,monkey则不会延时
--pct-touch 后面接触摸事件的百分比。(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)
--pct-motion 后面接动作事件的百分比。(动作事件由屏幕上某处的一个down事件、一系列的伪随机事件和一个up事件组成)。
--pct-trackball 后面接轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)。
--pct-nav 后面接“基本”导航事件百分比(导航事件主要来自方向输入设备的上,下,左,右事件)
--pct-majornav 后面接“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)
--pct-syskeys 后面接“系统”按键事件的百分比(这些按键通常被保留,由系统使用,如Home、Back、StartCall、End Call及音量控制键)。
--pct-appswitch 后面接启动Activity的百分比。在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法。
--pct-anyevent 调整其它类型事件的百分比。它包罗了所有其它类型的事件,如:按键、其它不常用的设备按钮、等等。
约束类 -p 如果用此参数指定了一个或几个包,Monkey将只允许系统启动这些包里的Activity。如果你的应用程序还需要访问其它包里的Activity(如选择取一个联系人),那些包也需要在此同时指定。如果不指定任何包,Monkey将允许系统启动全部包里的Activity。要指定多个包,需要使用多个-p选项,每个-p选项只能用于一个包。
-c 如果用此参数指定了一个或几个类别,Monkey将只允许系统启动被这些类别中的某个类别列出的Activity。如果不指定任何类别,Monkey将选择下列类别中列出的Activity:Intent.CATEGORY_LAUNCHER或Intent.CATEGORY_MONKEY。要指定多个类别,需要使用多个-c选项,每个-c选项只能用于一个类别。
调试类 --dbg-no-events 设置此选项,Monkey将执行初始启动,进入到一个测试Activity,然后不会再进一步生成事件。为了得到最佳结果,把它与-v、一个或几个包约束、以及一个保持Monkey运行30秒或更长时间的非零值联合起来,从而提供一个环境,可以监视应用程序所调用的包之间的转换。
--hprof 设置此选项,将在Monkey事件序列之前和之后立即生成profiling报告。这将会在data/misc中生成大文件(~5Mb),所以要小心使用它。
--ignore-crashes 通常,当应用程序崩溃或发生任何失控异常时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成。
--ignore-timeouts 通常,当应用程序发生任何超时错误(如“ApplicationNot Responding”对话框)时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成。

一条常用的Monkey命令

adb shell monkey -v -v -v -p [PackageName] --ignore-crashes --ignore-timeouts --ignore-security-exceptions --monitor-native-crashes --ignore-native-crashes --throttle 1000 100000 > monkey.txt

Monkey的特点

综合上面的描述,使用Monkey如下特点:

1.Monky测试使用的事件流数据流是随机的,不能进行自定义。
2.可对MonkeyTest的对象,事件数量,类型,频率等进行设置。

通过自然语言开发Monkey自动化脚本

因为命令行运行每次需要修改不同的参数,这样操作不是很灵活,我们可以写段代码来驱动。为了让脚本的可读性更高,我们使用BDD的方式来做。BDD的好处就是可以在自然语言描述中修改参数就能直接运行程序,并可以数据驱动。对于团队协作,或者新人了解业务特别方便。下面借助工具来实现这些操作:

因为脚本用JavaScript,开发工具可以使用CukeTest(http://cuketest.com)
执行引擎可以借助 adbkit 来实现。步骤如下:

  • 环境搭建
    配置sdk (请自行网上查阅资料本机安装sdk)
    安装node.js库 adbkit(https://github.com/openstf/adbkit)

  • 创建项目
    打开CukeTest,文件新建-新建项目;项目类型选择基本项目,填写项目信息,完成创建即可。
    在项目的根目录下执行npm install adbkit --save 完成abdkit 库的安装。
    关于abdkit 可以参考GitHub https://github.com/openstf/adbkit

  • 设置超时时间
    由于需要持续长时间按去运行monkey 脚本检测应用的稳定性,所以设置超时时间长一些

编辑support/env.js

const { setDefaultTimeout } = require('cucumber')

setDefaultTimeout(1000 * 1000)

编辑feaure文件

# language: zh-CN
功能: monkey 稳定性测试
调用monkey脚本 检测手机app原生计算器稳定性

场景: 设计并调用monkey脚本
假如apppackage"com.android.calculator2"
同时设置运行随机数值为10000
当我希望基本导航事件中占用比例为"10"
同时触摸事件在所有事件中所占的比例为"70"
同时每个操作步骤之间的间隔为1000毫秒
并且忽略程序崩溃或者发生异常
那么手机序列号为"192.168.181.101:5555"运行1000次脚本

如果你想修改monkey 脚本的参数,直接修改feature文件中的参数即可。

  • 编写自动化脚本
const { Given, When, Then } = require('cucumber');

var adb = require('adbkit');
var client = adb.createClient();

//// Your step definitions /////

var command = ' monkey '

Given(/^apppackage"([^"]*)"$/, async function (packagename) {
command = command + "
-p " + packagename
});

Given(/^设置运行随机数值为(\d+)$/, async function (seed) {
command += "
-s " + seed
});

When(/^我希望基本导航事件中占用比例为"
([^"]*)"$/, async function (nav) {
command += ' --pct-touch ' + nav});

When(/^触摸事件在所有事件中所占的比例为"([^"]*)"$/, async function (touch) {
command += "
--pct-touch " + touch
});

When(/^忽略程序崩溃或者发生异常$/, async function () {
command += "
--ignore-crashes "
});

When(/^每个操作步骤之间的间隔为(\d+)毫秒$/, async function (ms) {
command += "
--throttle " + ms
});

Then(/^手机序列号为"
([^"]*)"运行(\d+)次脚本$/, async function (deviceid, num) {
command += " " + num;

return client.shell(deviceid, command)
// Use the readAll() utility to read all the content without
// having to deal with the events. `output` will be a Buffer
// containing all the output.
.then(adb.util.readAll)
.then(function (output) {
console.log('[%s] %s', device.id, JSON.stringify(output.toString().trim()))
})

});
  • 运行脚本 点击运行feature 文件,即可看到monkey 自动去操作模拟器的计算器

如果要对多个应用做不同的Monkey测试,只需要在CukeTest中将这个场景一键转换成场景大纲,再添加多行数据就行了。真正实现了通过数据驱动做Monkey测试。

欢迎大家一起交流学习。

共收到 4 条回复 时间 点赞

var adb = require('adbkit')var client = adb.createClient()
^

SyntaxError: Unexpected token var
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:606:28)
at Object.Module._extensions..js (module.js:653:10)
at Module.load (module.js:561:32)
at tryModuleLoad (module.js:504:12)
at Function.Module._load (module.js:496:3)
at Module.require (module.js:586:17)
at require (internal/module.js:11:18)
at supportCodePaths.forEach.codePath (D:\Program Files (x86)\LeanPro\CukeTest\resources\app.asar\out\cucumber.js:1:145953)
at Array.forEach ()
at Cli.getSupportCodeLibrary (D:\Program Files (x86)\LeanPro\CukeTest\resources\app.asar\out\cucumber.js:1:145920)
at Cli.run (D:\Program Files (x86)\LeanPro\CukeTest\resources\app.asar\out\cucumber.js:1:146268)
at l.runWithDisplayListener (D:\Program Files (x86)\LeanPro\CukeTest\resources\app.asar\out\cucumber.js:7:59389)
at l.runFeatureFile (D:\Program Files (x86)\LeanPro\CukeTest\resources\app.asar\out\cucumber.js:7:59243)
at

请问报这个错误,是哪里出问题了

这个是为了更容易读懂吗?

imzack #3 · August 31, 2018 作者
renfenghui 回复

不好意思,我代码复制的格式有问题,
不是

var adb = require('adbkit')var client = adb.createClient()

应该是

var adb = require('adbkit');
var client = adb.createClient();
imzack #4 · August 31, 2018 作者
simple 回复

嗯,行为驱动测试的理念是为了减少大家的沟通成本,提高团队的协作能力。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up