ATX ATX 结合 Maxim 实现多设备并行执行压力测试

linpengcheng · December 10, 2018 · Last by 咖啡咖 replied at March 07, 2019 · 2931 hits

介绍

之前分享的 UI 自动化测试框架: 基于 ATX-Server 的 UI 自动化测试框架 实现了多设备的并行测试,能够自动生成报告并日志输出到指定的文件夹下面.

在此基之上,增加了基于 maxim 的压测功能.多设备的并行执行都是基于之前的基础之上.
能够实现 app 卸载重新安装之后,账号登录,进入到指定页面之后再执行 monkey 压力测试

GitHub 地址还是这个:https://github.com/pengchenglin/ATX-Test

实现方式

在用 maxim 的时候,发现在在启动 uiautomator2 的时候,maxim 就没法用了,原因是 uiautomator2 和 Maxim 工作时都需要连接系统的 AccessibilityService.
在看 uiautomator2 的文档的时候发现是可以启停 android-uiautomator-server

d.service("uiautomator").stop()     # 暂停
d.service("uiautomator").start()    # 启动

atx-agent 提供执行设备端 shell 命令的功能,操作 maxim 其实用 shell 就够了.
push 相关的 jar 和配置文件到手机上;pull 运行完成后的 log 日志内容

相关链接

WiFi 无线拉起执行 APP 稳定性 / 压力测试,免 USB 连线
基于 Android Monkey 二次开发,实现高速点击的 Android Monkey 自动化工具 fastmonkey - 代号 Maxim
浅谈自动化测试工具 python-uiautomator2

流程解析

工程目录


ATX_Test/Public/Maxim文件夹下存放了 maxim 运行是需要的所有文件,运行的时候会将指定文件 push 到 Android 设备中.

ATX_Test/Public/maxin_monkey.py是对 maxim 的 shell 命令的封装和执行 monkey 操作的两个方法封装,具体的参数定义在里面写比较清楚,可以直接去看代码
maxin_monkey.py 下 run_monkey 的代码如下

def run_monkey(cls, monkey_shell, actions=False, widget_black=False):
    '''
    清理旧的配置文件并运行monkey,等待运行时间后pull log文件到电脑
    :param monkey_shell: shell命令 uiautomatortroy 时 max.xpath.selector文件需要配置正确
    :param actions: 特殊事件序列 max.xpath.actions文件需要配置正确
    :param widget_black: 黑控件 黑区域屏蔽 max.widget.black文件需要配置正确
    :return:
    '''
    log.i('MONKEY_SHELL:%s' % monkey_shell)
    cls.clear_env()
    cls.push_jar()
    if monkey_shell.find('awl.strings') != -1:
        cls.push_white_list()
    if monkey_shell.find('uiautomatortroy') != -1:
        cls.push_selector()
    if actions:
        cls.push_actions()
    if widget_black:
        cls.push_widget_black()
    cls.set_AdbIME()
    runtime = monkey_shell.split('running-minutes ')[1].split(' ')[0]
    log.i('starting run monkey')
    log.i('It will be take about %s minutes,please be patient ...........................' % runtime)
    # restore uiautomator server
    cls.d.service('uiautomator').stop()
    time.sleep(2)
    cls.d.shell(monkey_shell)
    time.sleep(int(runtime) * 60 + 30)
    log.i('Maxim monkey run end>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
    # restore uiautomator server
    cls.d.service('uiautomator').start()

然后就是在ATX_Test/Public/Driver.py下增加了run_maxim实现 maxim 的多设备执行操作

ATX_Test/Monkey下是登录操作的脚本和最终的运行 maxim_monkey 的执行文件,运行就执行 monkey_run.py 就好了

工作流程

ATX_Test/Monkey/monkey_run.py 的代码:

from Public.Drivers import Drivers
from Public.Report import *
from Public.maxim_monkey import Maxim
import unittest
from Monkey import login_steps

if __name__ == '__main__':
    # back up old report dir 备份旧的测试报告文件夹到TestReport_backup下
    data = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
    backup_report('./MaximReport', './MaximReport_History', data)
    cases = unittest.TestSuite()
    cases.addTest(login_steps.abcd('test_install_login'))

    command = Maxim().command(package='com.github.android_app_bootstrap', runtime=1, mode='uiautomatordfs',throttle=500,options=' -v -v ', whitelist=True)

    Drivers().run_maxim(cases=cases, command=command, actions=True, widget_black=False)

还是使用了 macaca 的 bootstrap app 作为 demo 演示
执行 monkey 前 卸载重装,账号登录的操作直接写成了 unitest 的脚本,这样原来的 UI 自动化写的脚本直接拿来用,其实很简单的几行就搞定了

class abcd(unittest.TestCase, BasePage):
    @classmethod
    @setupclass
    def setUpClass(cls):
        cls.d.app_stop_all()

    @testcase
    def test_install_login(self):
        '''安装启动android_app_bootstrap'''
        self.d.app_uninstall(pkg_name)
        self.local_install(apk_path)
        self.d.app_start(pkg_name)
        self.set_fastinput_ime()
        time.sleep(3)
        login.login_page().input_username('username')
        login.login_page().input_password('password')
        login.login_page().click_login_btn()

运行 maxim 的命令通过 maxim_monkey.py 下的 Maxim().command 来实现组装
最后执行 Public.Drivers().run_maxim 来开始运行

运行 maxim 的主要代码如下:

def _run_maxim(run, cases, command, actions, widget_black):
    log = Log()
    log.set_logger(run.get_device()['model'], os.path.join(run.get_path(), 'client.log'))
    log.i('udid: %s', run.get_device()['udid'])

    # set cls.path, it must be call before operate on any page
    path = ReportPath()
    path.set_path(run.get_path())

    # set cls.driver, it must be call before operate on any page
    base_page = BasePage()
    if 'ip' in run.get_device():
        base_page.set_driver(run.get_device()['ip'])
    else:
        base_page.set_driver(run.get_device()['serial'])

    try:
        # run cases
        base_page.d.shell('logcat -c')  # 清空logcat
        if cases:
            run.run_cases(cases)
        Maxim().run_monkey(monkey_shell=command,actions=actions, widget_black=widget_black)

        base_page.d.shell('logcat -d > /sdcard/logcat.log')
        time.sleep(1)
        base_page.d.pull('/sdcard/logcat.log', os.path.join(path.get_path(), 'logcat.log'))
        base_page.d.pull('/sdcard/monkeyerr.txt', os.path.join(path.get_path(), 'monkeyerr.txt'))
        base_page.d.pull('/sdcard/monkeyout.txt', os.path.join(path.get_path(), 'monkeyout.txt'))

        base_page.set_original_ime()
        base_page.identify()
    except AssertionError as e:
        log.e('AssertionError, %s', e)

设定好报告存放的路径,初始化设备之后,执行相关的操作:

1.清空 logcat
2.存在 UI 自动化操作 cases 的执行 cases
3.开始运行 monkey(push 相关的文件到手机,执行 monkey shell 命令)
4.monkey 执行完成,将logcat.log monkeyerr.txt monkeyout.txtpush 到电脑上报告存放的路径

输出结果


在 monkey_run.py 同级目录下,会将结果存在于一时间命名的文件夹下,不同的设备存在在不同的设备文件夹下

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

前段时间也做了同样的的功能,感觉他们结合起来用真的特别棒!


1.第一个红框那有点不懂,请大神帮忙解释一下
2.第二个框那,好像有点错误,_db 根本没有 insert_multiple 这个方法,而 table 类中才有 insert_multiple 这个方法

咖啡咖 回复

看一下 tinydb 库的用法 这段代码是小红书我复制过来的

这个如果有遇到崩溃的时候,他的崩溃信息是在日志里面体现吗??怎么体现的

咖啡咖 回复

base_page.d.pull('/sdcard/logcat.log', os.path.join(path.get_path(), 'logcat.log'))
base_page.d.pull('/sdcard/monkeyerr.txt', os.path.join(path.get_path(), 'monkeyerr.txt'))
base_page.d.pull('/sdcard/monkeyout.txt', os.path.join(path.get_path(), 'monkeyout.txt'))

会有一个执行的 logcat 文件 可以在这里看

monkeyerr.txt 应该也会有报错信息的


有点不懂这个 run 是哪里来的,怎么直接就掉了 get_device() 方法了

咖啡咖 回复


这边来的

你这个支持黑名单吗??

咖啡咖 回复

支持白名单 你改成黑名单也行




我这么改了 不对,帮我看看还要改什么地方,谢谢

咖啡咖 回复


-v-v 后面的那个就可以不用加了 直接 blacklist=Ture 就好了
其实这个 commad 方法只是用来组装执行命令而已 你调用之后输入看看格式对不对就行

你这个应该回出来重复的 2 次--blacklist 的东西

麻烦加你个 qq 吧

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