Android 自动化测试(Python)
1). 工具
uiautomator2:获取界面对应控件
weditor:网页版查看 UI 界面
2). uiautomator2
- 安装
/usr/local/opt/python/bin/python3.7 -m pip install -U uiautomator2 --user
- 初始化(必需)- 需要访问Github
/usr/local/opt/python/bin/python3.7 -m uiautomator2 init
3). weditor
- 安装
/usr/local/opt/python/bin/python3.7 -m pip install -U weditor --user
- 启动
/usr/local/opt/python/bin/python3.7 -m weditor
4). 显示界面
- 连接 Android 模拟器或者真机
- 启动 weditor,点击左上角connect, 点击后出现绿色小叶子
- 在网页查看 Android 界面,点击中间 Reload 蓝色按钮,显示效果如下图
效果图.png
5). 支持的按键名称
home
back
left
right
up
down
center
menu
search
enter
delete ( or del)
recent (recent apps)
volume_up
volume_down
volume_mute
camera
power
6). 手势
- click: 单击
- double_click: 双击
- long_click: 长按
- swipe: 滑动
- drag: 拖拽
- touch:
d.touch.down(10, 10) # 模拟按下
time.sleep(.01) # down 和 move 之间的延迟,自己控制
d.touch.move(15, 15) # 模拟移动
d.touch.up() # 模拟抬起
7). Selector
- text, textContains, textMatches, textStartsWith
- className, classNameMatches
- description, descriptionContains, descriptionMatches, descriptionStartsWith
- checkable, checked, clickable, longClickable
- scrollable, enabled,focusable, focused, selected
- packageName, packageNameMatches
- resourceId, resourceIdMatches
- index, instance
- 获取组件的孩子
d(className="android.widget.ListView").child(text="Bluetooth")
- 获取组件的兄弟
d(text="Google").sibling(className="android.widget.ImageView")
- 相对位置
d(A).left(B), selects B on the left side of A.
d(A).right(B), selects B on the right side of A.
d(A).up(B), selects B above A.
d(A).down(B), selects B under A.
8). 文本框控制
# 获取文本内容
d(text="xxx").get_text()
# 设置文本内容
d(text="xxx").set_text("My text...")
# 清空文本内容
d(text="xxx").clear_text()
9). 特殊的 UI 手势
- 拖拽到另一个点
d(text="xxx").drag_to(x, y, duration=0.5)
- 从UI对象的中心滑动到其边缘(1 steps 大约 5ms)
d(text="xxx").swipe("right")
d(text="xxx").swipe("left", steps=10)
d(text="xxx").swipe("up", steps=20)
d(text="xxx").swipe("down", steps=20)
- 从一点到另一个点
d(text="xxx").gesture((sx1, sy1), (sx2, sy2), (ex1, ey1), (ex2, ey2))
- 两点手势
# 从边缘到中心
d(text="xxx").pinch_in(percent=100, steps=10)
# 从中心到边缘
d(text="xxx").pinch_out()
- 等待 UI 显示和隐藏
# 等待直到显示
d(text="xxx").wait(timeout=3.0)
# 等待直到隐藏
d(text="xxx").wait_gone(timeout=1.0)
- fling
# 竖直fling,默认为垂直
d(scrollable=True).fling()
# 水平fling
d(scrollable=True).fling.horiz.forward()
# 竖直fling,反方向
d(scrollable=True).fling.vert.backward()
# 水平fling,按步数滚动
d(scrollable=True).fling.horiz.toBeginning(max_swipes=1000)
# 竖直fling到结尾
d(scrollable=True).fling.toEnd()
- 滚动
# 默认垂直滚动
d(scrollable=True).scroll(steps=10)
# 水平滚动
d(scrollable=True).scroll.horiz.forward(steps=100)
# 竖直回滚
d(scrollable=True).scroll.vert.backward()
# 水平开始滚动
d(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000)
# 滚动到结尾
d(scrollable=True).scroll.toEnd()
# 滚到直到 UI 显示
d(scrollable=True).scroll.to(text="Security")
10). 观察弹窗
- ANR
d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
.click(text="Force Close")
- 提示框
d.watcher("ALERT").when(text="OK").click()
11). Toast
- 显示
d.toast.show("Hello world")
- 读取
assert "Short message" in d.toast.get_message(5.0, default="")
12). xpath
d.xpath("//android.widget.TextView").wait(10.0)
13). QQ 示例
# -*-coding:utf-8-*-
# /usr/local/opt/python/bin/python3.7
"""
1. 安装uiautomator2模块
/usr/local/opt/python/bin/python3.7 -m pip install -U uiautomator2 --user
文档:https://github.com/openatx/uiautomator2
/usr/local/opt/python/bin/python3.7 -m uiautomator2 init
2. 安装网页查看器
/usr/local/opt/python/bin/python3.7 -m pip install -U weditor --user
# 运行
/usr/local/opt/python/bin/python3.7 -m weditor
"""
import uiautomator2 as u2
# 判断是否为当前主函数
if __name__ == "__main__":
# 1. 连接设备
d = u2.connect('192.168.2.20:7912')
# 2. 设置 QQ 包名
p = 'com.tencent.mobileqq'
# 3. 安装 QQ
# d.app_install(
# 'https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk')
# 4. 启动 QQ
d.app_start(p)
# 延时 5 秒
d.implicitly_wait(5000.0)
# 打印设置延时时间
print("wait timeout: ", d.implicitly_wait()) # get default implicit wait
# 获取 app 信息
appInfo = d.app_info(p)
print("app info: ", appInfo)
# 保存 app 图标
# img = d.app_icon(p)
# 存放路径:与 qq.py 同级
# img.save('icon.png')
# 本地文件 -> 内存卡
# d.push('test.txt', '/sdcard/')
# 内存卡 -> 本地
# d.pull('/sdcard/test.txt', 'test1.txt')
# 命令行
# 当前路径
output, exit_code = d.shell("pwd", timeout=60)
print('output: ', output)
print('exit_code: ', exit_code)
# 查看所有文件
output, exit_code = d.shell(["ls", "-l"])
print('output: ', output)
print('exit_code: ', exit_code)
# 手机信息
print('手机信息:', d.info)
# 获取屏幕信息
print('屏幕信息:', d.window_size())
# 等待界面显示
# default timeout 10.0 seconds
# d.wait_activity(".activity.LoginActivity", timeout=10)
# 获取设备***
print('设备***: ', d.serial)
# 获取 WLAN IP
print('WLAN IP:', d.wlan_ip)
# 获取设备信息
print('设备信息:', d.device_info)
"""
# 熄灭屏幕-锁屏
d.screen_off()
# 延时
d.implicitly_wait(1000.0)
# 点亮屏幕-解锁
d.screen_on()
"""
# 点击 HOME 键
# d.press('home')
# 点击返回键
# d.press('back')
# press keycode 0x07('0') with META ALT(0x02)
# d.press(0x07, 0x02)
"""
# 锁屏
d.screen_off()
# 延时
d.implicitly_wait(1000.0)
# 解锁
d.unlock()
"""
# 获取屏幕方向
print('屏幕方向:', d.orientation)
"""
# 锁定方向
d.freeze_rotation(False)
# 设置屏幕方向
# 延时
d.implicitly_wait(5000.0)
# 方向左
d.set_orientation("l") # or "left"
# 延时
d.implicitly_wait(5000.0)
# 方向右
d.set_orientation("r") # or "right"
# 延时
d.implicitly_wait(5000.0)
# 自然
d.set_orientation("n") # or "natural"
"""
# 截屏
# d.screenshot("home.png")
# 获取组件个数
# len(d(text="登录"))
# 进入登录页
d(resourceId='com.tencent.mobileqq:id/btn_login').click()
# 输入用户名
d(description='请输入QQ号码或手机或邮箱').set_text('输入自己的 QQ 账好')
# 输入密码
d(resourceId="com.tencent.mobileqq:id/password").set_text('输入自己的 QQ 密码')
# 登录
d(resourceId="com.tencent.mobileqq:id/login").click()
5. 停止 QQ
d.app_stop(p)
pass