1. 为什么选择uiautomator2替代Appium?

做过手机自动化测试的朋友应该都体验过Appium的"重量级"——光是配置Java环境、Android SDK、Node.js这一套下来,半天时间就没了。我在去年一个紧急项目中,就因为团队新成员的开发环境配置问题,导致整个自动化测试流程延迟了3天。而uiautomator2最大的优势就是轻量,它直接通过Python调用Android原生测试框架,省去了中间层,实测从零开始搭建环境到运行第一个测试用例,最快只要15分钟。

这个库底层基于Google官方UiAutomator,但做了两个关键改进:一是用Python封装了所有API,不用再写Java代码;二是采用HTTP-RPC通信,比Appium的JSON Wire Protocol更高效。我做过对比测试,同样的100次元素点击操作,uiautomator2比Appium快2-3倍。特别是在持续集成环境中,这种性能优势会被放大。

2. 5分钟快速搭建测试环境

2.1 基础组件安装

首先确保你的设备满足:

  • Android 4.4+(建议用Android 9+)
  • Python 3.6+(实测3.8.2稳定)

安装核心组件只需要两条命令:

pip install uiautomator2
pip install weditor==0.6.4  # 特别注意版本兼容性

遇到过编码问题的同学可以这样解决:

set PYTHONUTF8=1  # Windows临时设置编码
export PYTHONIOENCODING=utf-8  # Linux/Mac

2.2 设备连接实战技巧

初始化设备时有个坑要注意:

uiautomator2 init  # 会自动安装atx-agent

如果卡在"installing apk"阶段,可能是USB调试授权没通过,建议:

  1. 检查手机是否弹出授权对话框
  2. 尝试重启adb服务:adb kill-server && adb start-server
  3. 换用WiFi连接模式

我更喜欢用WiFi连接,避免USB线松动问题:

import uiautomator2 as u2
d = u2.connect('192.168.1.100')  # 手机IP
print(d.info)  # 验证连接

3. 元素定位的三大神器

3.1 Weditor可视化定位

启动Weditor后有个实用技巧:

weditor --adb  # 自动关联adb设备

在浏览器界面中:

  1. 开启"实时刷新"模式
  2. 使用"强制刷新"按钮应对动态元素
  3. 右键元素可生成Python定位代码

3.2 精准定位策略

这些是我总结的最佳实践:

# 首选resourceId定位(最快)
d(resourceId="com.xx:id/btn_confirm").click()

# 复合定位提高稳定性
d(className="Button", text="确定", instance=0)

# 处理列表元素的技巧
for item in d(className="ListView").child():
    print(item.info['text'])

3.3 智能等待机制

解决元素加载超时问题的方案:

# 自定义等待策略
el = d(text="加载中").wait(timeout=15)  # 最长等15秒
if el.exists:
    el.click()
else:
    raise TimeoutError("元素未出现")

# 全局设置超时
u2.settings['wait_timeout'] = 20  # 默认10秒

4. 完整测试框架搭建实战

4.1 核心模块封装

建议按这个结构组织代码:

framework/
├── device_controller.py  # 设备管理
├── page_objects/         # 页面元素
├── test_cases/           # 测试逻辑  
└── utils/                # 工具类

关键设备管理代码示例:

class AndroidDevice:
    def __init__(self, serial=None):
        self.d = u2.connect(serial or os.getenv('DEVICE_SERIAL'))
        self._setup_device()

    def _setup_device(self):
        self.d.set_new_command_timeout(300)  # 防止ADB超时
        self.d.implicitly_wait(10)  # 隐式等待
        
    def screenshot(self, name):
        path = f"logs/{datetime.now():%Y%m%d}/{name}.jpg"
        self.d.screenshot(path)
        return path

4.2 典型测试用例实现

以微信发消息为例:

def test_send_wechat_message():
    device = AndroidDevice()
    wechat = WeChatPage(device)
    
    try:
        wechat.launch()
        wechat.search_contact("测试群")
        wechat.input_message("自动化测试消息")
        wechat.click_send()
        assert "消息发送成功" in device.get_toast()
    finally:
        device.stop_app("com.tencent.mm")

4.3 异常处理方案

这些异常处理代码能帮你省下80%的调试时间:

def safe_click(element):
    for _ in range(3):  # 重试3次
        try:
            if element.exists:
                element.click()
                return True
        except Exception as e:
            print(f"点击异常: {str(e)}")
            time.sleep(1)
    raise ElementClickError("点击操作失败")

5. 高级技巧与性能优化

5.1 速度提升秘籍

这几个参数调优让我的测试速度提升40%:

# 在conftest.py中全局设置
u2.settings.update({
    'operation_delay': 0.5,  # 操作间隔
    'xpath_debug': False,     # 关闭xpath调试
    'wait_timeout': 8,       # 比默认10秒更激进
})

5.2 并行测试方案

用pytest-xdist实现多设备并行:

# pytest.ini配置
[pytest]
addopts = -n 3  # 根据设备数量调整

# 设备动态分配
def pytest_configure(config):
    config.device_pool = [AndroidDevice(s) for s in get_available_devices()]

5.3 自定义插件开发

扩展uiautomator2的能力:

class GesturePlugin:
    def __init__(self, d):
        self.d = d
        
    def swipe_to_bottom(self):
        """滑动到底部"""
        width, height = self.d.window_size()
        self.d.swipe(width/2, height*0.8, width/2, height*0.2)

# 注册插件
d.register_plugin(GesturePlugin(d))

6. 常见问题解决方案

6.1 元素识别失败排查

我整理的检查清单:

  1. 检查Weditor中元素是否可见
  2. 尝试关闭手机动画(开发者选项)
  3. 禁用MIUI优化(小米手机)
  4. 切换定位策略(优先用resourceId)
  5. 增加等待时间和重试机制

6.2 跨版本兼容处理

用版本嗅探实现兼容:

def handle_different_versions(d):
    sdk_version = d.info['display']['width']
    if sdk_version >= 29:  # Android 10+
        d.shell("settings put global hidden_api_policy 1")
    else:
        d.shell("pm grant com.github.uiautomator android.permission.DUMP")

6.3 日志与报告增强

集成Allure生成漂亮报告:

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item):
    outcome = yield
    report = outcome.get_result()
    
    if report.when == 'call':
        device = item.funcargs['device']
        allure.attach(device.screenshot("error"), 
                     name="失败截图",
                     attachment_type=allure.attachment_type.JPG)

在持续集成环境中,这套框架已经稳定运行超过2000次自动化测试任务,平均执行时间比原来Appium方案缩短35%。最让我惊喜的是它的稳定性——在最近一次长达72小时的稳定性测试中,没有出现任何内存泄漏问题。如果你正在寻找一个既轻量又强大的移动测试方案,不妨试试这个组合。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐