自动化工具 (无需 Root) 基于 Android Monkey 二次开发,实现高速点击的 Android Monkey 自动化工具 fastmonkey - 代号 Maxim

zhangzhao_lenovo · 发布于 2018年01月19日 · 最后由 zhangzhao_lenovo 回复于 2018年02月23日 · 1937 次阅读
本帖已被设为精华帖!

打造一款快速高效且高度可复用的android自动化测试工具 (qq群 :608824162)

主页入口 请点我
https://github.com/zhangzhao4444/Maxim

优势

  1. 高速点击,每秒 10-15 action!
  2. 多平台兼容! 同时兼容Android 5-8
  3. 轻量极简!

如何使用

  1. adb push  framework.jar  monkey.jar  文件到 /sdcard
  2. 执行  adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60

参数说明

  1. tv.panda.test.monkey.Monkey 主调入口  无需修改
  2. -p com.panda.videoliveplatform  待测appid
  3. 策略模式

    --uiautomatormix 混合模式(70%控件解析随机点击,其余30%按原Monkey事件概率分布) 
    --pct-uiautomatormix n 可自定义混合模式中控件解析事件概率
    --uiautomatordfs DFS深度遍历算法(优化版)(注 Android5不支持dfs)
    非以上两种为原始Monkey策略

  4. 执行时长
    --running-minutes 60        执行60分钟monkey

  5. 场景细粒度控制
    --act-whitelist-file  /sdcard/awl.strings    自定义Activity白名单
    例:

    com.panda.videoliveplatform.activity.WelcomeActivity
    com.panda.videoliveplatform.activity.SplashWakeActivity
    com.panda.videoliveplatform.activity.MainFragmentActivity
    com.panda.videoliveplatform.activity.LiveRoomActivity
    

    锁定跳转只可进入其中的某个Activity
    --act-blacklist-file        同上

  6. 其他参数及用法同原始Monkey

特性简介

a. 速度快 每秒10-15个Action事件
界面控件解析算法通过改造底层framework,直接使用AccessibilityNodeInfo并优化减化其调度流程,解析速度控制在50ms内,可对界面变化做快速反应。

{
    val clickable = ArrayList<AccessibilityNodeInfo>() 
    collectClickable(clickable, root)   //递归算法生成node树结构
    ......
    val node = clickable[random.nextInt(count)]
    val nodeRect = Rect()
    node.getBoundsInScreen(nodeRect)  //选取其中某个node的 rect ,随机点击其中某point

    generateClickEventAt(nodeRect, 0L)
}

b. Android全平台兼容
兼容Android5,6,7,8各系列。通过反射原理动态解析各平台Api差异,使用一套逻辑兼容全系列。

{
    Class<?> clazz = mAm.getClass();
    String name = "setActivityController";    //存在差异的api
    Method method = findMethod(clazz, name, android.app.IActivityController.class);     //反射动态search api
    if (method != null) {
        ......
    }
    method = findMethod(clazz, name, android.app.IActivityController.class, boolean.class);
    if (method != null) {
        ......
}

c. 防跳出
控件解析时获取进程推栈Top Activity,按非白即黑立即执行切回。各事件执行时按特有逻辑屏蔽掉状态栏,防止误操作。

{
     ......
     cn = this.mDevice.mAm.getTasks(1, 0).get(0).topActivity    //取top activity
     if (cn != null) currentPackage = cn.getPackageName()

     if (!MonkeyUtils.packageFilter.isPackageValid(currentPackage!!)) {    //判断非白即黑
         this.mQ.clear()
         this.generateActivity()
    ......
}

d. 防休眠
休眠时自动检测并唤醒屏幕。

{
    ......
    if (!this.mPM!!.isInteractive) {      //判断处于休眠中
        ......
        val i = Runtime.getRuntime().exec(arrayOf("input", "keyevent", "26")).waitFor()    //唤醒设备
    ......
}

e. 熔断机制
当事件按某个特有模式固定执行一段时间时则自动触发熔断开始自拉活,防止假死。如重复点击同一位置n秒。

private fun isBlocked(): Boolean{
    val jam = true
    ......
    val last = actionsHistory.last()
    for (i in 2..30){    //重复点击n次 触发熔断
        if (mVerbose > 1) Logger.log("last action is ${actionsHistory.size-1} code = $last, action${actionsHistory.size-i} code = ${actionsHistory[actionsHistory.size-i]}")
        if (last != actionsHistory[actionsHistory.size-i]){    
            return false
        }
    }
    //其他熔断
    .....
}

f. 场景细粒度
引入Activity黑白名单,可控制限定在某些场景内。如只测试某几个相关页面。

private inner class ActivityController : IActivityController.Stub() {
    override fun activityStarting(intent: Intent, pkg: String): Boolean {
        var allowActivity = true
        if (MonkeyUtils.activityFilter.hasValidActivitys()){
            val currentActivity: String? = try {intent.component.className} catch (e:Exception){null}
            if (currentActivity != null){
                allowActivity = MonkeyUtils.activityFilter.checkEnteringActivity(currentActivity)     //通过filter的才允许跳转
            }
            Logger.log("// Activity : ${currentActivity} in Intent")
        }
        ......
   }
    ......
}

g. 随机自动输入
检测当遇到可输入模式时,按设定(ape.string)或随机输入键盘事件。如输入666或2333弹幕
随机输入 需要提前安装adbkeyboard
https://github.com/senzhk/ADBKeyBoard

{ 
    ......
    val inputMethodVisbleHight = this.mDevice.mIMM!!.getInputMethodWindowVisibleHeight()    //存在键盘输入栏
    if (inputMethodVisbleHight <= 0) return
    //注入键盘事件
    try { generateRandomKeyEvents() }catch (e : Exception){ }
    ......
}    

h. 崩溃堆栈自动保存
当崩溃(crash、oom)发生时自动抓取,并存于/sdcard/crash-dump.log

{ 
    override fun appCrashed(processName: String, pid: Int, shortMsg: String, longMsg: String, timeMillis: Long, stackTrace: String): Boolean {
            ......
            writeDumpLog("// CRASH: $processName (pid $pid) (dump time: $dateStr)")
            writeDumpLog("// Build Time: ${Build.TIME}")
            writeDumpLog("// ${stackTrace.replace("\n", "\n// ")}")
            ....
}    

todo

  1. 特殊事件序列 - 已完成
  2. 引入GT性能测试
  3. 控件黑名单

** 其他 **

扫盲贴: https://testerhome.com/topics/11884

常见问题排查

  1. 小米手机未开启 “开发者选项” -> "USB调试(安全设置) 允许通过usb调试修改权限或模拟点击"。
    开启后ok 。报错log如下图

  2. accessibilityservice 被其他驱动占用 agent未注销。如使用过atx 未执行unregister。
    执行unregister后OK。报错log 如下图,或无log

  3. 厂商修改造成 dex 无法load ,maxim启动后就退出。实际什么都未执行。无log输出。 logcat如下图。此问题暂时待查

update

#29楼
支持特殊事件序列 max.xpath.actions

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 31 条回复
156e5d

先赞一个👍

153681

给力,用起来

9485

先赞一个

4楼 已删除
3d19a1

学习一下,之前想改一直没真正找到点,没敢下手。

3d19a1

期待一下特殊事件序列

982

高速点击不应该是核心测试需求的诉求吧,实际的压测需要有页面缓冲、动效显示、图片加载的处理间隔,还应有等待回收逻辑处理完成,所以还是模拟用户行为间隔更重要。否则会引起研发不认可的bug及内存泄露压力不够的问题。

3170
982sandman 回复

高速是指解析界面算法。如果觉得event太快可以自行添加 Throttle。 速度不够何谈压力

104 seveniruby 将本帖设为了精华贴 01月23日 20:47
982

哦,原来指的是算法能力上能支持高速点击。实际压测还是要分压测场景和压测目的具体平衡事件比例,过快的操作更多考验的是未完成事件的中断,往往会发生用户正常操作不会遇到的bug。
而针对内存占用的压力还是需要图片加载,视频缓冲,合理节奏下的GC释放场景的正常测试。对app压测评估、对app压测bug补漏、通过app压测系统和底层服务等不同目的的方案设计还是有区别的。建议针对不同场景的使用可以做下建议性参数配置实例。

8331

你好楼主使用你的工具 替换包名后 运行 提示

   ..                    ..:.
           ..t..     Maxim      .h..
            ..i..  . ....... .  ..si
              sandroidmonkeystreste
              .sttoolMaxim.thistool.
           .helpyoutofoundappcrash.thi
         ..stooluserandomordfsalgorithm:.
        .smonkeyMaxim machine gunmonkey..
      ..monkey,..,monkeymonkeym,..,onkeym.
      .onkeymon..keymon.keymonke..ymonkeym.
      ,onkeymonkeymonkeymonkeymonkeymon.key.
     .monkeymonkeymonkeymonkeymonkeymonkeym.
     .onkeymonkeymonkeythxforphdguxiaotian.:
     .anythingUcancontactpanda_zzaqq77227005
      .                                   . 

      .                                   . 

[Maxim] *** ERROR // : No activities found to run, monkey aborted.
14017

666,实践一下

3170
8331sysayy 回复

monkey命令参数可能输错了。把你的adb shell 那条命令发来看看

12235

很感谢分享,想问一下如何修改monkey源码进行二次开发?主要对这个过程感兴趣,网上这方面的资料很少,方便的话可以详细说一下过程吗?小白也想试试自己改一下

3170
122359688e 回复

加q群说吧。这个简单一两句说不清楚

12235

额 不知道Q群是多少?方便告知一下吗

12235

看到了 谢谢

8331
仅楼主可见
3170
8331sysayy 回复

加q说吧

8331

497703927

10014

源码方便放到github上么?

3170

后续会开源的,请关注

16042

移动终端需要root权限吧

3170
16042paomo 回复

不需要root

16042
仅楼主可见
3170
16042paomo 回复

“开发者选项” -> "USB调试(安全设置) 允许通过usb调试修改权限或模拟点击" 这个可否打开了?

16042

"USB调试(安全设置) 允许通过usb调试修改权限或模拟点击"这个打开后就可以了,给力!👍

4f9cc2 harsayer Maxim-高速 Android Monkey 工具使用记录 中提及了此贴 02月03日 11:04
3170 zhangzhao_lenovo Android 的 Monkey Test 疑问 中提及了此贴 02月05日 20:04
3170 zhangzhao_lenovo monkey 稳定性测试 中提及了此贴 02月05日 20:08
3170 zhangzhao_lenovo Android 性能测试之 Monkey 中提及了此贴 02月05日 20:09
507703
122359688e 回复

方便给下群号吗 我也想加群 了解下,自带的monkey太随机了

3170
507703limzhang 回复

qq群 :608824162

3170

2018.02.23 update

  1. (MIX模式) 增加支持 特殊事件序列

需要配置 max.xpath.action 文件
案例:

[
{
    "prob": 1,
    "activity":"tv.panda.account.activity.WebLoginActivity",
    "actions": [
        {
            "xpath": "//*[@class='android.widget.EditText']",
            "action": "INPUTTEXT",
            "text": "13810751000",
            "index": 0,
            "throttle": 300
        },
        {
            "xpath": "//*[@class='android.widget.EditText']",
            "action": "INPUTTEXT",
            "text": "123400",
            "index": 1,
            "throttle": 300
        },
        {
            "xpath": "//*[@content-desc='登录' and @class='android.view.View']",
            "index": 0,
            "action": "CLICK",
            "throttle": 1000
        }]
},
{
     "prob": 1,
     "actions": [
     {
             "xpath": "//*[@class='android.view.View']",
             "index": 0,
             "action": "SWIPE",
             "args": "10,1000,800,1000,100",
             "throttle": 3000
         }]
 },
{
     "prob": 1,
     "actions": [
     {
             "xpath": "//*[@class='android.view.View']",
             "index": 0,
             "action": "TOUCH",
             "args": "500,1000",
             "throttle": 1000
         }]
}
]

上述包含3个特殊事件
发生概率 prob =1 为100%发生
仅当 当前activity 为 tv.panda.account.activity.WebLoginActivity 时或无activity配置时做事件查找
xpath 为待查找控件的xpath 支持复杂型xpath,支持 index 索引选择
throttle 为该特殊步骤执行完后sleep n 毫秒
Action 支持
1.Click 点击匹配到的xpath控件
2.INPUTTEXT 在匹配到的xpath控件中输入 text 指定字符,输入需要提前安装adbkeyboard
3.TOUCH 点击指定坐标 args = (x,y)
4.SWIPE 按执行路径滑动 args = (x1,y1,x2,y2,step)

注 配置完成后请贴在 json.cn 检查格式,注意” : , 非中文

4f9cc2

更新后 发现
是ape.strings 对应现在的 max.strings
ape.xpath.actions 对应现在的 max.xpath.actions

还多了一个max.config 是配置什么的

cmd@TR:~/workspace/git/Maxim$ cat max.config 
max.startAfterNSecondsofsleep = 6000
max.wakeupAfterNSecondsofsleep = 4000

3170
4f9cc2harsayer 回复

帮助文档里有写这个,配置命名我规范了下 之前太随意了

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册