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

2020-10-09  本文已影响0人  Kingtester

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乱点也能拉回去了呢,<( ̄▽ ̄)/

上一篇下一篇

猜你喜欢

热点阅读