Android 自动化测试(Python)

1). 工具
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 蓝色按钮,显示效果如下图
Android 自动化测试(Python)
效果图.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