Android 开发自测试 - Monkeyrunner

Author Avatar
Aaron Von 6月 22, 2017

我们在做 Android 开发自测试的时候除了最基本的 LLT,也可以放出一只野猴子来测试我们的代码健壮性以及程序的稳定性。不过今天我们要当一回驯兽师,训练一只聪明一点儿的猴子 -> Monkeyrunner

为什么要用 Monkeyrunner?

Monkey 工具其实只是一只野猴子,想想你把手机给你三岁儿子玩儿的场景吧,他也就只会一顿瞎摁,操作是没有逻辑性的。所以一般我们实际环境中只会将其作为压力测试的工具。而 Monkeyrunner 干的活可就多了,它就像是你儿子长到 5 岁了,可以让他做一些连贯、需要逻辑处理能力的小事了。


Monkeyrunner 的环境搭建

闲话少说,Monkeyrunner 的环境搭建还是很简单的:

  1. Android SDK
  2. Java JDK
  3. Python

就是这么简单粗暴!


Hello World

下面我们来看一个 Monkeyrunner 版的 Hello World

# Talk is cheap, show me the code.
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

device = MonkeyRunner.waitForConnection()

package = 'com.pioneer.aaron.dolly'

activity = 'com.pioneer.aaron.dolly.MainActivity'

activityToRun = package + '/' + activity

device.startActivity(activityToRun)

MonkeyRunner.sleep(1)
exp_main = device.takeSnapshot()

device.touch(520, 400, MonkeyDevice.DOWN_AND_UP)

MonkeyRunner.sleep(1)
device.press('KEYCODE_BACK', MonkeyDevice.DOWN_AND_UP)

MonkeyRunner.sleep(1)
actual_main = device.takeSnapshot()

print "Return to MainActivity:", exp_main.sameAs(actual_main, 0.9)

# exp_main.writeToFile('~/Desktop/screenshot1.png', 'png')

Monkeyrunner 提供了三个模块,分别为:

  • MonkeyRunner: 用于连接 Android 设备,真机/模拟器均可;

  • MonkeyDevice: 用于与设备的交互。操作的事件、安装 APK 什么的都通过它;

  • MonkeyImage: 镜像?不,真的就是的’图像’,不过这个图像可是 Monkeyrunner 非常重要的一环。

稍微过一下我们上面的代码:

  1. MonkeyRunner.waitForConnection() 获取到了我们的设备对象,
  2. device.startActivity(activityToRun) 启动了一个指定的 Activity,对了这个 APP 在这里,欢迎 PR
  3. screenshot = device.takeSnapshot() 截了一张图。

这个时候重点来了[敲黑板],MonkeyImage 可以用指定的偏差率来对比像素之间的差异以确定图片的相似性。说中文就是:我们可以用一张期望正确的图片来对比实际的图片,如果一样(误差范围内),那么就证明我们的操作成功了。

在上面的代码中,我点击了一下屏幕 坐标(520, 400),然后按了一下返回键 KEYCODE_BACK,这个时候我们当然期望的是进入返回栈中第二个界面,在这里也就是我们的 MainActivity。然后使用 MonkeyImage.sameAs() 判断返回成功与否。

当然如此简单的一个用例,返回了

$ Return to MainActivity: True


尾巴


以前在学校中写程序,只要能跑起来就行了,充其量是个 DEMO 的阶段,对健壮性、稳定性都不做过多要求。但是现在真正开始写商业软件才发现,一个 NPE 可能就是几条产品线的停工。虽然 Defensive Programming 会让代码看上去面目可憎,但这确实是实际环境中必不可少的一环,这都是无数血泪换来的教训。

当然现在 SDK 已经 自带了 EasyMonkeyDevice 模块,可以让测试代码更加 ‘人性化’ 一点儿。就放在下次再写了吧~