从零玩转Android自动化:UIAutomator2与Weditor实战指南
第一次接触移动端自动化测试时,我盯着满屏的代码手足无措——那些按钮和输入框在代码里到底该怎么表示?直到发现了Weditor这个"可视化外挂",配合UIAutomator2的Python API,终于让元素定位变得像搭积木一样直观。本文将带你用最接地气的方式,从环境配置到复杂操作,一步步掌握这套黄金组合。
1. 环境准备:搭建你的自动化工作台
工欲善其事,必先利其器。在开始之前,我们需要准备以下环境:
- Python 3.7+:推荐使用最新稳定版
- Android设备/模拟器:需开启开发者选项和USB调试
- ADB工具:确保设备能通过
adb devices正常识别
安装核心工具只需两条命令:
pip install -U uiautomator2 weditor安装完成后,初始化设备连接:
import uiautomator2 as u2 # 通过USB连接(推荐) d = u2.connect_usb() # 或者通过WiFi连接 # d = u2.connect('192.168.1.100')提示:首次运行会自动在设备安装ATX代理应用,如遇安装失败可手动下载apk推送
2. Weditor:可视化定位的神兵利器
Weditor就像给代码戴上了AR眼镜,它能实时显示界面元素树,并支持:
- 点击查看元素属性
- 自动生成定位代码
- 实时刷新界面结构
启动Weditor只需运行:
python -m weditor浏览器会自动打开本地服务页面(默认http://localhost:17310)。连接设备后,你会看到这样的元素结构:
<android.widget.FrameLayout> <android.widget.TextView text="登录" resource-id="com.example:id/login_btn"/> <android.widget.EditText hint="请输入用户名" class="android.widget.EditText"/> </android.widget.FrameLayout>实用技巧:
- 按
F5刷新当前界面 - 右键元素可复制XPath
Ctrl+点击可同步操作设备
3. 元素定位的六脉神剑
掌握以下定位方式,能解决99%的元素查找问题:
3.1 通过resourceId定位(最可靠)
d(resourceId="com.taobao:id/search_button").click()3.2 通过文本定位
# 完全匹配 d(text="确认").click() # 包含匹配 d(textContains="确").click()3.3 通过类名定位
d(className="android.widget.Button").click()3.4 组合定位(解决元素冲突)
d(className="android.widget.Button", text="提交").click()3.5 XPath定位(复杂结构首选)
d.xpath('//*[@resource-id="com.taobao:id/tabs"]/android.widget.RelativeLayout[3]').click()3.6 相对定位(动态元素处理)
d(text="商品").right(className="android.widget.Image").click()注意:优先使用resourceId,其次考虑组合定位,XPath应作为最后选择
4. 高级操作技巧实战
4.1 手势操作:滑动与拖拽
# 从(x1,y1)滑动到(x2,y2),持续0.5秒 d.swipe(500, 1500, 500, 500, 0.5) # 拖拽操作 d.drag(300, 800, 300, 200, 0.5)滑动优化技巧:
- 获取屏幕尺寸动态计算坐标:
width, height = d.window_size() start_x, end_x = width/2, width/2 start_y, end_y = height*0.8, height*0.2 d.swipe(start_x, start_y, end_x, end_y)4.2 输入法控制
# 启用快速输入(绕过系统输入法) d.set_fastinput_ime(True) d.send_keys("自动化测试") d.set_fastinput_ime(False) # 清空输入框的三种方式 d.clear_text() # 方法1 d.send_keys("") # 方法2 d(resourceId="input").set_text("") # 方法34.3 等待策略
# 隐式等待(全局生效) d.implicitly_wait(10) # 显式等待(推荐) d(text="加载中").wait(timeout=15) # 等待元素出现 d(text="完成").wait_gone(timeout=20) # 等待元素消失 # 自定义条件等待 def is_tab_loaded(): return d(text="首页").exists d.wait_until(is_tab_loaded, timeout=30)5. 实战案例:电商APP自动化测试
让我们用一个完整的电商APP测试流程串联所学知识:
import uiautomator2 as u2 import time d = u2.connect_usb() d.implicitly_wait(10) # 启动应用 d.app_start("com.taobao.taobao") try: # 跳过开屏广告 if d(text="跳过").exists: d(text="跳过").click() # 搜索商品 d(resourceId="com.taobao:id/searchEdit").click() d.set_fastinput_ime(True) d.send_keys("无线键盘") d.press("enter") # 筛选商品 d(text="销量").click() time.sleep(2) # 等待排序完成 # 进入第一个商品详情 d.xpath('//*[@resource-id="com.taobao:id/recycler_view"]/android.view.View[1]').click() # 加入购物车 d(text="加入购物车").click() d(text="确定").click() # 返回首页 d.press("back") d.press("back") finally: d.app_stop("com.taobao.taobao")常见问题处理:
- 弹窗拦截:
if d(text="允许").exists: d(text="允许").click()- 异常重试:
def safe_click(selector, max_retry=3): for i in range(max_retry): try: selector.click() return True except: time.sleep(1) return False- 截图记录:
d.screenshot("before_search.png")6. 性能优化与调试技巧
6.1 提升执行速度
# 关闭动画提升速度 d.settings['operation_delay'] = (0, 0) # 操作后延迟 d.settings['wait_timeout'] = 10 # 元素等待超时 # 禁用不必要的监听 d.disable_toast_check()6.2 调试技巧
# 打印当前页面层级(调试用) print(d.dump_hierarchy()) # 启用详细日志 import logging logging.basicConfig(level=logging.INFO) # 检查元素是否存在 if not d(text="确定").exists: print("未找到确认按钮")6.3 设备管理
# 获取设备信息 print(d.info) # 屏幕操作 d.screen_on() # 点亮屏幕 d.screen_off() # 关闭屏幕 d.press("home") # 返回桌面 # 文件传输 d.push("local.txt", "/sdcard/remote.txt") d.pull("/sdcard/remote.txt", "local_copy.txt")在实际项目中,我发现将常用操作封装成工具类能大幅提升效率。比如创建一个MobileOperator类,封装点击、输入、滑动等基础操作,加入自动重试和日志记录功能。当某个元素的定位方式频繁变更时,只需修改工具类中的一处定义即可。