美文网首页
老司机带你玩转APP的Monkey测试

老司机带你玩转APP的Monkey测试

作者: Kingtester | 来源:发表于2020-10-09 17:39 被阅读0次

    1,解压ADB压缩包,在cmd窗口下,启动adb服务:

    image.png
    image.png

    2,使用USB将手机和电脑连接,并将手机设置为开发者模式,使用adb devices命令查看当前连接设备:

    image.png

    3,执行monkey命令

    monkey是只皮猴子,是安卓中的一个UI压力测试工具,重在测试稳定性。但是在运用monkey测试app,深受其乱点的烦恼,虽然在指定app的情况下,依然会随机点到app外面,然后再也回不来了,大大降低了其作用。

    查阅了网上不少文章,在看这篇文章的时候,突然有了点启发https://blog.csdn.net/liyu520131414/article/details/6935777

    这篇文章的思路就是在monkey在执行时候,另外开启一个程序对其进行轮询,如果不在指定的页面,就随机将它拉到app里指定的页面。

    当然java我不太懂,只是大致看了下,在执行的时候也没有达到理想的效果,也许是我执行的方式不对,因此参照他的思路,用python写了个轮询脚本,当然功能上也比他写的缩减了不少,暂时只是对连接在电脑上一台手机进行此操作,详细优化步骤如下。

    1.monkey脚本

    先来看下原先我们执行的脚本

    adb shell monkey -p cn.citytag.mapgo -s 2333 --pct-touch 70 --pct-motion 30 --ignore-crashes --ignore-timeouts --monitor-native-crashes --throttle 200 -v -v 500000 >E:\logs\monkey0903.txt

    monkey命令的含义就不细说了,网上有超多文章进行了详细解释,绿色--pct-touch 70 --pct-motion 30这两个命令是后面增加的,一个代表点击,一个代表滑动,两个加起来是100,代表不会进行其他事件操作,如轨迹事件,导航事件等等,指定这两种操作后,就极大的降低了monkey点到被测app外面的概率

    另外还是会有在执行向下滑动的命令时,打开了通知栏,然后又开始了瞎点的操作。这时可在执行monkey命令之前,先执行禁用通知栏的命令

    adb shell settings put global policy_control immersive.full=*

    解禁命令:adb shell settings put global policy_control null

    这里对monkey的参数做一个注解:
    命令参数
    可以使用命令 adb shell monkey -help 查看命令参数

    1、参数: -p

    用于约束限制,用此参数指定一个或多个应用。指定应用之后,monkey将只允许系统启动指定的app;如果不指定应用,将允许系统启动设备中的所有应用。

    指定一个应用: adb shell monkey -p com.ifeng.news2 100

    指定多个应用:adb shell monkey -p com.ifext.news –p com.ifeng.news2 100

    不指定应用:adb shell monkey 100

    2、参数:-c

    用于约束限制,用此参数指定了一个或几个类别,Monkey将只允许系统启动被这些类别中的某个类别列出的Activity。如果不指定任何类别,Monkey将选择下列类别中列出的Activity:Intent.CATEGORY.LAUNCHER 或 Intent.CATEGORY.MONKEY。要指定多个类别,需要使用多个-c选项,每个-c选项只能用于一个类别。

    3、参数:-v

    用于指定反馈信息级别(信息级别就是日志的详细程度),总共分3个级别:

    默认级别 Level 0:-v

    adb shell monkey -p com.ifeng.news2 –v 100:说明仅提供启动提示、测试完成和最终结果等少量信息

    日志级别 Level 1:-v -v

    adb shell monkey -p com.ifeng.news2 –v -v 100:说明提供较为详细的日志,包括每个发送到Activity的事件信息

    日志级别 Level 2:-v -v -v

    adb shell monkey -p com.ifeng.news2 –v -v –v 100:说明最详细的日志,包括了测试中选中/未选中的Activity信息

    4、参数: -s

    伪随机数生成器的seed值。如果用相同的seed值再次运行Monkey,它将生成相同的事件序列

    Monkey 测试1:adb shell monkey -p com.ifeng.news2 -s 10 100

    Monkey 测试2:adb shell monkey -p com.ifeng.news2 –s 10 100

    两次测试的效果是相同的,因为模拟的用户操作序列(每次操作按照一定的先后顺序所组成的一系列操作,即一个序列)是一样的。

    5、参数: --throttle<毫秒>

    用于指定用户操作(即事件)间的延时,单位是毫秒

    adb shell monkey -p com.ifeng.news2 --throttle 5000 100

    6、参数: --ignore-crashes

    用于指定当应用程序崩溃时(Force& Close错误),Monkey是否停止运行。如果使用此参数,即使应用程序崩溃,Monkey依然会发送事件,直到事件计数完成。

    adb shellmonkey -p com.ifeng.news2 --ignore-crashes 1000

    测试过程中即使程序崩溃,Monkey依然会继续发送事件直到事件数目达到1000为止

    adb shellmonkey -p com.ifeng.news2 1000

    测试过程中,如果acg程序崩溃,Monkey将会停止运行

    7、参数: --ignore-timeouts

    用于指定当应用程序发生ANR(Application No Responding)错误时,Monkey是否停止运行。如果使用此参数,即使应用程序发生ANR错误,Monkey依然会发送事件,直到事件计数完成。

    adb shellmonkey -p com.ifeng.news2--ignore-timeouts 1000

    8、参数: --ignore-security-exceptions

    用于指定当应用程序发生许可错误时(如证书许可,网络许可等),Monkey是否停止运行。如果使用此参数,即使应用程序发生许可错误,Monkey依然会发送事件,直到事件计数完成。

    adb shellmonkey -p com.ifeng.news2 --ignore-security-exception 1000

    9、参数: --kill-process-after-error

    用于指定当应用程序发生错误时,是否停止其运行。如果指定此参数,当应用程序发生错误时,应用程序停止运行并保持在当前状态(注意:应用程序仅是静止在发生错误时的状态,系统并不会结束该应用程序的进程)。

    adb shellmonkey -p cn.emoney.acg --kill-process-after-error 1000

    10、参数: --monitor-native-crashes

    用于指定是否监视并报告应用程序发生崩溃的本地代码。

    adb shellmonkey -p cn.emoney.acg --monitor-native-crashes 1000

    11、参数: --pct-{+事件类别}{+事件类别百分比}

    用于指定每种类别事件的数目百分比(在Monkey事件序列中,该类事件数目占总事件数目的百分比)

    --pct-touch{+百分比}:

    调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)

    adb shell monkey -p com.ifeng.news2 --pct-touch 10 1000

    --pct-motion {+百分比}:

    调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随件机事和一个up事件组成)

    adb shell monkey -p com.ifeng.news2 --pct-motion 20 1000

    --pct-trackball {+百分比}:

    调整轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)

    adb shell monkey -p com.ifeng.news2 --pct-trackball 30 1000

    --pct-nav {+百分比}:

    调整“基本”导航事件的百分比(导航事件由来自方向输入设备的up/down/left/right组成)

    adb shell monkey -p com.ifeng.news2 --pct-nav 40 1000

    --pct-majornav {+百分比}:

    调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)

    adb shell monkey -p com.ifeng.news2 --pct-majornav 50 1000

    操作事件简介
    Monkey所执行的随机事件流中包含11大事件,分别是触摸事件、手势事件、二指缩放事件、轨迹事件、屏幕旋转事件、基本导航事件、主要导航事件、系统按键事件、启动Activity事件、键盘事件、其他类型事件。Monkey通过这11大事件来模拟用户的常规操作,对手机App进行稳定性测试。下面让我们来详细了解这11大事件。

    1.触摸事件
    触摸事件是指在屏幕某处按下并抬起的操作,可通过--pct-touch参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到。 该事件由一组Touch(ACTION_DOWN)和Touch(ACTION_UP)事件组成,在手机上看到实际操作类似于点击。

    2.手势事件
    手势事件是指在屏幕某处的按下、随机移动、抬起的操作,即直线滑动操作。可通过--pct-motion参数来配置其事件百分比。

    该事件是由一个ACTION_DOWN事件、一系列ACTION_MOVE事件和一个ACTION_UP事件组成的,在手机上看到的实际操作是一个没有拐弯的直线滑动操作。

    3.二指缩放事件
    二指缩放事件是指在屏幕上的两处同时按下,并同时移动,最后同时抬起的操作,即智能机上的放大缩小手势操作。可通过--pct-pinchzoom参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

    该事件起始是一个ACTION_DOWN事件和一个ACTION_POINTER_DOWN事件,即模拟两个手指同时点下;中间是一系列的ACTION_MOVE事件,即两个手指同时在屏幕上直线滑动;结束是由一个ACTION_POINTER_UP事件和一个ACTION_UP事件组成的,即两个手指同时放开。

    4.轨迹事件
    轨迹事件是由一个或多个随机的移动组成的,有时会伴随着点击。很早之前的Android手机带有轨迹球,这个事件就是模拟的轨迹球的操作。现在的手机几乎都没有轨迹球,但轨迹球事件中包含曲线滑动操作,如果被测程序需要曲线滑动时可以选用此参数。可通过--pct-trackball参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

    该事件是由一系列的Trackball(ACTION_MOVE)事件组成的,观察手机上的操作,即为一系列的曲线滑动操作。

    5.屏幕旋转事件
    屏幕旋转事件是一个隐藏事件,在Android官方文档中并没有记录这个事件。它其实是模拟的Android手机的横屏和竖屏切换。可通过--pct-rotation参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件由一个rotation事件组成,其中degree表示的是旋转方向,顺时针旋转,0表示旋转90度的方向,1表示旋转180度的方向,2表示旋转270度的方向,3表示旋转360度的方向。在执行过程中,可以看到手机屏幕在横竖屏之间不断地切换。

    6.基本导航事件
    基本导航事件是指点击方向输入设备的上、下、左、右按键的操作,现在手机上很少有上、下、左、右按键,这种事件一般用得比较少。可通过--pct-nav参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

    该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的就是上、下、左、右四个方向按键。

    7.主要导航事件
    主要导航事件是指点击“主要导航”按键的操作,这些按键通常会导致UI界面中的动作,如键盘的中间键、回退按键、菜单按键。可通过--pct-majornav参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的按键就是中间键和菜单键。

    8.系统按键事件
    系统按键事件是指点击系统保留使用的按键的操作,如点击Home键、返回键、音量调节键等。可通过--pct-syskeys参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的就是上面说到的几个系统按键。

    9.启动Activity事件
    启动Activity事件是指在手机上启动一个Activity的操作。在随机的时间间隔中,Monkey将执行一个startActivity()方法,作为最大限度上覆盖被测包中全部Activity的一种方法。可通过--pct-appswitch参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Switch操作组成的,从手机上看,上面的操作实际是打开了com.android.settings这个应用的一个com.android.settings.Settings的Activity界面。

    10.键盘事件
    键盘事件主要是一些与键盘相关的操作。比如点击输入框、键盘弹起、点击输入框以外区域、键盘收回等。可通过--pct-flip参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 如日志所示,这里主要是键盘的打开和关闭操作。

    11.其他类型事件
    其他类型事件包括了除前面提到的10种事件外其他所有的事件,如按键、其他不常用的设备上的按钮等。可通过--pct-anyevent参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的按键就是其他的一些系统按键,如字母按键、数字按键等。因为现在手机很少带字母按键或数字按键,所以这个事件一般使用得比较少。

    日志输出
    输出日志的方法:C:\Documents and Settings\Administrator>adb shell monkey -p 包名 -v 300 >D:\log.txt

    2.python脚本

    在完善了monkey脚本之后,还是会出现monkey点出去之后回不来的情况,那就写脚本吧。

    首先再一次明确目标,就是在monkey乱点点出了被测app后将其拉回来。

    直接先把代码丢上来。之前参照的文章里面利用xml作为配置文件,感觉挺简单的,也就直接用了。

    配置文件:config.xml

    <?xml version="1.0" encoding="utf-8"?>
    <config>
        <!-- 包名--> 
        <packagename>com.alashow.live</packagename>
        <!-- 主activity--> 
        <mainactivity>.MainActivity</mainactivity>
        <!-- 白名单activity--> 
        <whiteactivity>
        /.MainActivity,
        /cn.citytag.live.view.activity.LivePlayerActivity,
        /user.maopao.com.user.view.activity.mine.OthersHomePageActivity,
        /cn.citytag.live.view.activity.LiveFinishActivity,
        /cn.citytag.live.view.activity.LiveSearchActivity,
        /cn.citytag.live.view.activity.LiveRankingActivity,
        /cn.citytag.live.view.activity.LiveSubHomeActivity,
        /cn.citytag.live.view.activity.family.FamilyDetailActivity,
        /cn.citytag.live.view.activity.family.FamilyInformActivity,
        /cn.citytag.live.view.activity.family.FamilySettingActivity,
        /cn.citytag.live.view.activity.family.FamilyNoticeActivity,
        /cn.citytag.live.view.activity.tribe.TribeHomeActivity,
        /cn.citytag.live.view.activity.tribe.TribeWelfareActivity,
        /cn.citytag.live.view.activity.tribe.TribeShopActivity,
        /cn.citytag.live.view.activity.tribe.TribePackageActivity,
        /user.maopao.com.user.view.activity.bill.MyIncomeTotalDetailActivity,
        /cn.citytag.live.view.activity.LivePrepareActivity,
        /cn.citytag.live.view.activity.LiveSongEditActivity,
        /cn.citytag.live.view.activity.LiveNoticeActivity,
        /cn.citytag.base.widget.pictureselector.lib.PictureSelectorActivity
        </whiteactivity>
        <!-- 检查时间秒-->
        <interval>30</interval>
        <!-- 检查次数-->
        <count>10</count>
    </config>
    

    说明:没什么好说明的,都注释出来了,就是字面意思。

    python脚本:

    
    import os
    import re
    import xml.dom.minidom as xmldom
    import time
     
    class Mtest():
        def __init__(self):
            dom = xmldom.parse('config.xml')
            root = dom.documentElement
            self.packagename = root.getElementsByTagName('packagename')[0].firstChild.data
            self.mainactivity = root.getElementsByTagName('mainactivity')[0].firstChild.data
            self.interval = int(root.getElementsByTagName('interval')[0].firstChild.data)
            self.count = int(root.getElementsByTagName('count')[0].firstChild.data)
            self.whiteactivity = root.getElementsByTagName('whiteactivity')[0].firstChild.data.replace('\n','').replace(' ','').split(',')
     
        def get_now_activity(self):
            os.system("adb devices")
            content = os.popen('adb shell dumpsys activity  |findstr "mResumedActivity" ').read() #读取当前页面
            pattern = re.compile(r'/[a-zA-Z0-9\.]+')
            alist = pattern.findall(content)
            macitivity = self.packagename + '/' + self.mainactivity
            excuteshell = 'adb shell am start -n'+ macitivity
            if alist[0] not in self.whiteactivity:
                print('当前activity:'+alist[0])
                print('--------------开始返回主activity----------------')
                os.system(excuteshell)  #可拉回主页面
            else:
                print('当前activity:'+alist[0]+'不需要返回')
        
        def check(self):
            for _ in range(self.count):
                time.sleep(self.interval)
                self.get_now_activity()
     
    if __name__ == '__main__':
        test = Mtest()
        test.check()
    

    python脚本这里就要稍微说明下了:

    1.这里造了一个类,类的初始化里将config.xml里的内容读取过来运用了xml的一个库

    2.get_now_activity函数的作用是获取当前所在activity,判断其是否在白名单里,如果在就做操作,如果不在就拉回主页面(当然你可以设置拉回任何页面,甚至随机)

    os.system("adb devices") 这句不写也没关系,其实是获取当前连接的手机设备信息


    image.png

    adb shell dumpsys activity |findstr "mResumedActivity" 这条adb命令就是获取当前所在activity。如果你查看app的activity也很简单,你手机连着执行这条命令就可以了,这条命令执行后大致是这样的结果:


    image.png

    是不是数据不够单纯,与config.xml里的白名单数据相比是不是多了很多东西。

    pattern = re.compile(r'/[a-zA-Z0-9.]+')

    alist = pattern.findall(content)

    这时候可以用正则表达式将其取出输出alist[0],大致是这样的:


    image.png

    页面取出来之后就可以对其进行对比了,就是那个if判断

    接下来就是在判断到activity不在白名单里面之后,启动指定activity 利用这个命令'adb shell am start -n'

    3.最后一个函数就是利用config.xml里的配置,设置多长时间去轮询一次,然后一共轮询多少次。如30s轮询一次,那么一个小时就能轮询120次,假设你的monkey执行10个小时,那么你的轮询次数就要设置1200次。

    说了这么多,如何执行呢?

    1.先执行adb monkey的命令,将monkey跑起来

    2.执行python脚本

    3.仔细观察是不是就算monkey乱点也能拉回去了呢,<( ̄▽ ̄)/

    相关文章

      网友评论

          本文标题:老司机带你玩转APP的Monkey测试

          本文链接:https://www.haomeiwen.com/subject/bcalpktx.html