Appium stf+appium app 真机自动化平台实现

小酷 · 2020年08月27日 · 最后由 小酷 回复于 2021年04月06日 · 1144 次阅读

一、背景

之前搭建过一套 stf 的真机云测平台,最近在搞 app 自动化,想将 stf 与 appium 结合起来,搭建 app 真机自动化平台

二、架构图

架构图

【备注】:android-provider 功能已实现,ios-provider 功能待实现
【github 地址】:https://github.com/xglh/stf-appium-github

三、前期准备

1、手机上安装 Appium setting 等 appium 工具
2、部署 stf 服务,将手机接入 stf 网络,配置 stf-openapi token。注意,一定要先安装 Appium setting.apk 再接入 stf,不然会被 stf 还原

stf 部署参考文档:Android 部署IOS 部署
stf openapi 参考文档:stf-openapi
stf_devices
stf token

3、在 stf-provider 节点启动 appium 进程,一个 appium 进程绑定一台手机
#/bin/bash
nohup appium -p 4725 -U a32a6a4e --session-override > appium_a32a6a4e.log &
nohup appium -p 4726 -U b046c875 --session-override > appium_b046c875.log &
4、更改 driver.config 相应配置

四、基本工作流程

1、ftp 上传 app 到 provider 服务器
2、获取到可用的设备号 serial_no
# 设备连接状态
@unique
class DeviceStatusEnum(Enum):
    # adb连接正常
    ADB_READY = 'ADB_READY'
    # appium连接正常
    APPIUM_READY = 'APPIUM_READY'
    # stf连接正常
    STF_READY = 'STF_READY'
    # stf被占用
    STF_LOCKED = 'STF_LOCKED'

定义设备连接状态,APPIUM_READY,STF_READY 状态的设备才可用,优先返回 STF_READY 状态的设备

存在问题:
stf 暂时无法连接 android 10 系统的手机,但是绑定 appium 进程后也可以执行自动化脚本,故优先取 STF_READY 状态的设备,再取 APPIUM_READY 状态的设备

3、启动 driver,不指定 package 和 activity
desired_caps = {
                "platformName": self.platform,
                # appium setting不需要重复安装
                "skipServerInstallation": True,
                "skipDeviceInitialization": True,
                "deviceName": serial_no,
            }
driver = webdriver.Remote(appium_hub, desired_caps)
4、另开线程执行 adb install 命令,主进程通过 appium 点击继续安装按钮

confirm install

confirm permission

def _confirm_install_app(self, ssh_client: SSHClient, driver, serial_no):
    '''
    确认安装apk,需要根据不同机型适配
    :param ssh_client:ssh对象
    :param driver: driver对象
    :param serial_no: 设备编号
    :return: start_activity的opts参数,解决启动的activity不是指定的activity场景
    {
            'app_wait_package': 'com.android.packageinstaller',
            'app_wait_activity': '.permission.ui.GrantPermissionsActivity'
    }
    '''
    opts = {}
    # Redmi K20点击继续安装按钮
    if serial_no == 'ca352a47':
        # 启动后的activity与目标的不一样,需要设置start_activity方法的app_wait_package,app_wait_activity
        opts = {
            'app_wait_package': 'com.lbe.security.miui',
            'app_wait_activity': 'com.android.packageinstaller.permission.ui.GrantPermissionsActivity'
        }
        # 点击继续安装按钮
        WebDriverWait(driver, driver_wait_timeout, driver_wait_poll_frequency).until(
            EC.element_to_be_clickable((By.ID, "android:id/button2"))
        ).click()

    return opts

需要根据不同的机型适配确认安装操作和启动后的 app_wait_package,app_wait_activity 参数

5、启动 app
# 启动app
driver.start_activity(package_name, activity_name, appWaitDuration=10000, **opts)
time.sleep(1)
driver.switch_to.alert.accept()

stf locked.jpg

备注:此状态为设备占用状态,可以点击进去查看实时执行效果

以上流程实现 apk 安装到启动的流程

五、具体使用

from driver.driver_manager import DriverManager

app_path = 'xxx'
package_name, activity_name = 'xxx', 'xxx'
# 初始化并上传app
mDriverManager = DriverManager('android', app_path)

# 1、获取任意一个可用设备
driver_info = mDriverManager.get_driver(package_name, activity_name)
# 2、获取指定标号的设备
driver_info = mDriverManager.get_driver(package_name, activity_name, serial_no='ca352a47')
# 3、获取所有可用设备
driver_info = mDriverManager.get_driver(package_name, activity_name, acquire_all_device=True)
print(driver_info)
# 获取driver对象
for serial_no in driver_info:
    driver = driver_info[serial_no]['driver']
# 释放设备
mDriverManager.close()
'''
driver_info示例
{
    'ca352a47': {
        'device_status': 'STF_LOCKED',
        'appium_hub': 'http://1.1.1.1:4727/wd/hub',
        'ssh_client':  < driver.ssh_manager.SSHClient object at 0x000001EAD52CA860 > ,
        'release': '9',
        'sdk': '28',
        'manufacturer': 'Xiaomi',
        'model': 'Redmi K20',
        'wm_size': '1080x2340',
        'driver':  < appium.webdriver.webdriver.WebDriver(session = "246646ac-bf0a-49a8-8b99-7a68b40a7444") >
    }
}
'''

六、当前进展&后续开发拓展计划

当前完成度:

android 接入 5 台设备,完成测试 app 简单的登录退出 demo

后续开发拓展计划:

1、接入 ios-provider
2、完善框架日志和录屏功能
3、编写文档,准备团队内推广

共收到 6 条回复 时间 点赞

不错,模块划分挺清晰的,加油。

提个小建议,代码里不大建议 hard code 一些设备序列号之类的信息,这样以后换设备之类的调整起来会很麻烦。建议至少抽离到配置文件,可以的话做到自动适配不用写死在框架或脚本里。

恩,这个后边会调整的,目前还是想先接入实际项目试用下。

想问下 项目近况 跟使用情况 如何

白纸 回复

目前项目分为两块了,驱动层跟用例层。
驱动层的已经基本完成了,整合了 android 跟 ios,用脚本写了几条登录退出的用例。
用例层的话还在试用,我们的用例是在 web 平台上编写的,最近在推 app 元素定位规范,这个搞定了才会投入使用。

问一下你的 python 脚本是在 stf 所在服务器上执行么,还是本地执行

pablo 回复

python 脚本是在本地执行,服务器通过远程 hub 提供驱动

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