Android monkey 测试指定运行时间和稳定的设计思想

Android Monkey测试指定运行时间设计思路

目录

前言

1 基础知识

1.1 adb介绍

1.2 monkey参数选择

2 设计目标与思路

3 代码解析(python示例)

3.1 流程图

3.2 monkey执行逻辑函数

3.3 kill android monkey进程逻辑

3.4 检查monkey进程逻辑

4 适用场景

5 总结

6 完整代码


前言

在 Android 自动化稳定性测试中,adb shell monkey 是一个非常常用的工具。它通过大量随机事件模拟用户操作,能够帮助我们发现 android系统、App 在长时间运行中的潜在崩溃、ANR、卡顿等问题。

在实际测试中,压力测试不仅仅是monkey,还可以与其他测试结合形成稳定性压测工具。相较于关注monkey事件数量,monkey可能会存在异常终止,不会跑满事件数量,设计Monkey指定运行实践测试更为适用,可以很好地结合其他模块化测试形成稳定性测试策略。

本文将分享如何实现 Monkey 测试运行指定时长的设计思路与实现方法,并给出一套 Python 脚本的完整实现方案,帮助你构建一个更加稳定、可控的 Monkey 自动化测试。

1 基础知识

1.1 adb介绍

ADB(Android Debug Bridge)是 Android SDK 提供的一个命令行调试工具,用于与 Android 模拟器或真实设备进行通信。它是连接开发者与设备之间的重要桥梁,本文会用到如下adb命令:

adb device  # 查看当前设备号
adb shell  # 进入android调试,如需指定设备号使用adb -s {android} shell
adb shell pkill -9 <进程名>  # kill指定进程,本文用于kill monkey进程控制执行事件
adb shell "ps -A | grep monkey"  # 检查monkey进程是否正在运行
adb shell monkey -v --throttle 100 --ignore-crashes --ignore-timeouts 10000000  # 本文monkey命令使用示例

1.2 monkey参数选择

monkey工具支持很多参数,当前主要使用以下参数来设计:

  • -s:有多个android设备时,可指定android设备,只有一个android设备时,可忽略
  • -v:增加输出信息
  • -p:指定包名,可选
  • --throttle:设置事件间隔时间
  • --ignore-crashes:当应用发生崩溃时,monkey选择忽略崩溃,继续执行
  • --ignore-timeouts:忽略应用无响应(ANR)错误,不会终止 Monkey
  • 事件数量:Monkey 的最后一个参数是事件数,没有默认值,必须显式指定,设计monkey时间不关注,保证规定时间内存在事件,默认10000000

2 设计目标与思路

目标:让 Monkey 精准地跑指定时间,比如 2 小时

思路如下:

  1. python使用subprocess启动 Monkey 作为子进程

  2. 开始记录执行时间

  3. 当到达指定时间后,通过 adb 命令终止设备上的 Monkey 进程

  4. 如果未到达执行时间,monkey异常终止运行,则继续启动monkey,继续执行时间=指定时间 - 已执行时间

3 代码解析(python示例)

3.1 流程图

3.2 monkey执行逻辑函数

class AndroidMonkeyApi:

    @staticmethod
    def android_monkey(android, interval_time: int, package_name=None):
        if not android:
            print(f"android adb is None")
            return False
        if package_name:
            android_monkey_cmd = (f"adb -s {android} shell monkey -p {package_name} -v --throttle"
                                  f" {interval_time} --ignore-crashes --ignore-timeouts 10000000")
        else:
            android_monkey_cmd = (f"adb -s {android} shell monkey -v --throttle"
                                  f" {interval_time} --ignore-crashes --ignore-timeouts 10000000")
        try:
            print("start execute android monkey")
            subprocess.Popen(android_monkey_cmd)
            
    
    @staticmethod
    def android_monkey_execute(android, interval_time: int, execute_time: int, package_name=None) -> bool:
        """execute android monkey, by monitor and kill monkey process for appoint execute time

        Args:
            android: android adb
            interval_time: event interval time(millisecond)
            execute_time: event num
            package_name: appoint app package name
        """
        try:
            print("start execute android monkey")
            AndroidMonkeyApi.android_monkey(android, interval_time, package_name)  # 使用subprocess开始子进程运行monkey
            start_time = time.time()
            time.sleep(5)
            while True:
                if time.time() - start_time > execute_time:
                    for _ in range(10):
                        if AndroidMonkeyApi.kill_android_monkey(android):  # 当到达指定时间后,执行kill monekey进程
                            print("android monkey kill success, execute over")
                            break
                    break
                if AndroidMonkeyApi.check_android_monkey_not_run(android):  # 如果未到达执行时间,monkey异常终止运行,则继续启动monkey
                    executed_time = int(time.time() - start_time)
                    continue_time = execute_time - executed_time
                    print(f"android monkey is not running, continue execute {continue_time}s monkey")
                    AndroidMonkeyApi.android_monkey(android, interval_time, package_name)
            return True
        except Exception as e:
            print(f"android monkey error: {e}")
            return False

3.3 kill android monkey进程逻辑

    @staticmethod
    def kill_android_monkey(android) -> bool:
        """kill android monkey process"""
        if not android:
            print(f"android adb is None")
            return False
        try:
            print("start kill android monkey")
            # kill monkey进程名
            subprocess.run(f'adb -s {android} shell "kill -9 $(pgrep -f com.android.commands.monkey)"')
            # 检查monkey进程名是否存在,不存在则kill成功,返回True
            if AndroidMonkeyApi.check_android_monkey_not_run(android):
                print("kill android monkey success")
                return True
            else:
                return False
        except Exception as e:
            print(f"kill android monkey error: {e}")
            return False

3.4 检查monkey进程逻辑

    @staticmethod
    def check_android_monkey_not_run(android) -> bool:
        """check android monkey if running"""
        if not android:
            print(f"android adb is None")
            return False
        try:
            check_android_monkey_cmd = f'adb -s {android} shell "ps -A | grep monkey"'  
            # 检查monkey进程名是否存在
            process = subprocess.Popen(check_android_monkey_cmd,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       encoding='utf-8')
            stdout, _ = process.communicate(timeout=120)
            # 如果存在,说明monkey还在运行,返回False
            if "monkey" in stdout:  
                return False
            return True
        except Exception as e:
            print(f"check android monkey run error: {e}")

4 适用场景

  • 夜间稳定性持续测试

  • 长时间待机/后台测试

  • 自动化测试任务定时触发与终止

  • 精准配合其他稳定性测试场景构建压测策略

5 总结

Monkey 是 Android 原生稳定性测试的重要工具,而控制运行时长是提升其自动化能力的重要一步。在大型项目中,如开发虚拟化的android系统,有发生异常时会触发打包到db文件包到指定目录下,故构建稳定执行运行时长的Monkey测试尤为重要。

通过本文介绍的思路,你可以构建一个稳定、可控、适合大规模测试场景的 Monkey 运行方案。尤其适用于 CI 流水线、回归测试、系统级稳定性测试等场景。

6 完整代码

import subprocess
import time


class AndroidMonkeyApi:

    @staticmethod
    def android_monkey(android, interval_time: int, package_name=None):
        if not android:
            print(f"android adb is None")
            return False
        if package_name:
            android_monkey_cmd = (f"adb -s {android} shell monkey -p {package_name} -v --throttle"
                                  f" {interval_time} --ignore-crashes --ignore-timeouts 10000000")
        else:
            android_monkey_cmd = (f"adb -s {android} shell monkey -v --throttle"
                                  f" {interval_time} --ignore-crashes --ignore-timeouts 10000000")
        try:
            print("start execute android monkey")
            subprocess.Popen(android_monkey_cmd)
            
    
    @staticmethod
    def android_monkey_execute(android, interval_time: int, execute_time: int, package_name=None) -> bool:
        """execute android monkey, by monitor and kill monkey process for appoint execute time

        Args:
            android: android adb
            interval_time: event interval time(millisecond)
            execute_time: event num
            package_name: appoint app package name
        """
        try:
            print("start execute android monkey")
            AndroidMonkeyApi.android_monkey(android, interval_time, package_name)  # 使用subprocess开始子进程运行monkey
            start_time = time.time()
            time.sleep(5)
            while True:
                if time.time() - start_time > execute_time:
                    for _ in range(10):
                        if AndroidMonkeyApi.kill_android_monkey(android):  # 当到达指定时间后,执行kill monekey进程
                            print("android monkey kill success, execute over")
                            break
                    break
                if AndroidMonkeyApi.check_android_monkey_not_run(android):  # 如果未到达执行时间,monkey异常终止运行,则继续启动monkey
                    executed_time = int(time.time() - start_time)
                    continue_time = execute_time - executed_time
                    print(f"android monkey is not running, continue execute {continue_time}s monkey")
                    AndroidMonkeyApi.android_monkey(android, interval_time, package_name)
            return True
        except Exception as e:
            print(f"android monkey error: {e}")
            return False

    @staticmethod
    def kill_android_monkey(android) -> bool:
        """kill android monkey process"""
        if not android:
            print(f"android adb is None")
            return False
        try:
            print("start kill android monkey")
            # kill monkey进程名
            subprocess.run(f'adb -s {android} shell "kill -9 $(pgrep -f com.android.commands.monkey)"')
            # 检查monkey进程名是否存在,不存在则kill成功,返回True
            if AndroidMonkeyApi.check_android_monkey_not_run(android):
                print("kill android monkey success")
                return True
            else:
                return False
        except Exception as e:
            print(f"kill android monkey error: {e}")
            return False

    @staticmethod
    def check_android_monkey_not_run(android) -> bool:
        """check android monkey if running"""
        if not android:
            print(f"android adb is None")
            return False
        try:
            check_android_monkey_cmd = f'adb -s {android} shell "ps -A | grep monkey"'
            # 检查monkey进程名是否存在
            process = subprocess.Popen(check_android_monkey_cmd,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       encoding='utf-8')
            stdout, _ = process.communicate(timeout=120)
            # 如果存在,说明monkey还在运行,返回False
            if "monkey" in stdout:
                return False
            return True
        except Exception as e:
            print(f"check android monkey run error: {e}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值