python --自动化测试UiAutomator2

安装adb

安装adb后使用命令 adb devices 出现下图即可;
在这里插入图片描述

安装python依赖(uiautomator2,weditor)

pip install uiautomator2==2.16.23 weditor==0.6.8 -i https://pypi.doubanio.com/simple

# 在手机上安装 atx-agent 应用 

# 安装apk服务到手机上
python -m uiautomator2 init

解决安装weditor报错UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xad in position 825

在这里插入图片描述

脚本如下(可复制直接运行)

import os
 
# https://pypi.douban.com/simple  # 豆瓣镜像
# https://pypi.tuna.tsinghua.edu.cn/simple  # 清华镜像
 
mirror = " -i https://pypi.douban.com/simple"
 
os.system("python -m pip install --upgrade pip" + mirror)  # 更新 pip
os.system("pip install --pre -U uiautomator2" + mirror)  # 安装 uiautomator2
os.system("pip install --pre weditor" + mirror)  # 安装 weditor
os.system("python -m uiautomator2 init")  #安装 atx-agent 至手机

运行demo

import uiautomator2 as ui
import os
from loguru import logger

ui.DEBUG = False


class Connet(object):
    '''连接设备'''

    def __init__(self):
        self.devices_name_list: list = []  # 所有设备名称
        self.device: list = []  # 所有设备连接对象(每一个元素都是连接对象)
        os.environ['PATH'] += ';' + os.path.join(os.getcwd(), 'ADB')  # 设置adb为环境变量

    def _get_devices_name(self) -> None:
        '''提取设备名称'''
        devices_all = []
        for i in os.popen('adb devices').read().split('\n'):
            if i not in ('List of devices attached', ''):
                devices_all.append(i.split()[0])

        if len(devices_all) < 1:
            logger.error('检测不到设备')
        self.devices_name_list = devices_all

    def _connect(self):
        '''连接设备并提取设备对象至变量'''
        for device_name in self.devices_name_list:
            logger.warning(f'设备名称:【{device_name}】')
            self.device.append(ui.connect(device_name))
            logger.success(f'【{device_name}】...连接成功')

	def _start_vx(self):
        for device in self.device:
            try:
                device(scrollable=True).scroll.toEnd()   # 滑动至屏幕最底部
            except ui.exceptions.UiObjectNotFoundError as e:
                ...
            device(text='微信').click()  # 点击微信
           #  qujianma_assembly = device(resourceId="com.landicorp.jd.delivery:id/etPickUpCode")
           #  if not qujianma_assembly.exists:
           #      logger.error(f'找不到取件码组件,请切换至取件码页面')
           #     exit()

    def start(self, weishu):
        self._get_devices_name()
        self._connect()
        self._start_vx()
        
c = Connet()
c.start()

API方法详解

1.1连接设备
设备连接主要分为有线连接和无线连接,如下:

# 有线连接
d = u2.connect_usb(id)  # id 为 adb devices 命令中得到的设备 id
 
# 无线连接
d = u2.connect(ip)  # ip 为 手机 ip

说明:返回的 d 为连接句柄,通过 d 可以实现对手机的操作。

方法名称解析
d.app_install(‘http://domain.com/xxx.apk’)安装应用 【注】只能从 URL 安装
d.app_start(“app_package_name”, stop=False)打开应用(此处是包名)也可以用d(text='支付宝').click() ;stop参数为是否冷启动,默认为False
d.app_stop(“app_package_name”)关闭应用
d.app_stop_all()关闭所有应用
d.implicitly_wait(20)隐式等待20s,保证控件加载完成(可以全局设置)
d.app_uninstall(‘package_name’)卸载
d.app_current()获取当前正在运行的app的包名
d.app_info()获取app的信息
d.app_list_running()列出正在运行的app,这个也可以获取包名
d.app_clear(‘paceage_name’)清除app数据
d.info()获取设备基本信息
d.device_info()获取设备详细信息
d.window_size()获取设备大小
d.screenshot(‘d:/hello.png’)获取设备的截屏 传入电脑存放的路径
d.push(‘d:/hello.png’,‘/data/’)推送文件(上传文件) 第一个参数 PC需要上传的文件路径 第二个参数 手机端存放路径
d.pull(‘/data/hello.png’,‘d:/desktop/’)拉取文件和推送文件传参数相反
d.click_post_delay = 1.5全局设置每次单击UI后再次单击之间延迟1.5秒 默认无延迟
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
d(resourceId=元素ID).click()ID定位
d(text=“公众号:AirPython”).click()Text文本定位
d(description=“AirPython”).click()控件描述定位
d(className=“android.widget.TextView”).click()控件所属的类
d.xpath(“//*[@content-desc=‘AirPython’]”)Xpath定位
d(className=“android.widget.ListView”, resourceId=元素ID)组合定位
d(text=‘hello’, className=‘android.widget.TextView’)选text是’hello’,className 是’android.widget.TextView’ 的元素
d(text=“WiFi”).right(className=“android.widget.Switch”).click()选择"WiFi" 右侧的"switch" 同d(text="WiFi").right().click()left, right, top, bottom
d(text=“hello”, instance=0)获取第一个文本中带有“hello”的元素对象 同device(text="hello")[0]
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
d.wait_timeout = 10设置全局的超时时间 10s 只要设置了全局的超时时间,则其他的操作也会内置智能等待,不需要再进行任何操作
d.app_start(‘packagename’,wait=True)开启智能等待,即app完全打开后才执行后面代码
d.wait_activity()等待页面加载出来
d().wait()等待元素出现
d().wait_gone()等待元素消失
d().exists()等待元素是否存在
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
d.click()单击控件 支持xy坐标参数
d.double_click()双击控件 支持xy坐标参数
d.long_click(duration=0.5)长按控件支持xy坐标参数
d.set_text(text)输入文本
d.send_keys(text)输入文本广播式输入
d.set_fastinput_ime(True)打开关闭输入法 为True打开 否则关闭
d.clear_text()清除文本 d[index].clear_text() 定位的控件有多个,通过 index 指定某一个
d.get_text()获取文本 定位的控件只有一个,等价于 element[0].get_text()
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
device.screen_on()亮屏
device.screen_off()熄屏
device.press(“home”)首页
device.press(“back”)返回键
device.press(“left”)左移
device.press(“right”)右移
device.press(“up”)上划
device.press(“down”)下划
device.press(“center”)回到中间页
device.press(“menu”)菜单
device.press(“search”)搜索框
device.press(“enter”)回车键
device.press(“delete”)删除键
device.press(“recent”)打开最近的页面
device.press(“camera”)打开照相机
device.press(“power”)电源键
device.press(“volume_up”)声音调大
device.press(“volume_down”)声音调小
device.press(“volume_mute”)静音
d.orientation获取屏幕方向,取值为{“natural”, “left”, “right”, “upsidedown”}
d.freeze_rotation()锁定屏幕方向
d.freeze_rotation(True)解除锁定屏幕方向
d.set_orientation(“left”)向左转为横屏 d.set_orientation("right") # 向右转为横屏
device.screenshot(“screenshot.png”))截屏,支持自定义路径
d.screenrecord.start(“screenrecord.mp4”)录屏 需要从cv2 d.screenrecord.stop() 停止录屏
device.open_notification()打开通知栏

滑动操作

device(scrollable=True).fling(steps=5)   飞滑5,默认为1 手势向上,页面向下(正常翻页)
device(scrollable=True).fling.horiz.toBeginning()  横滑  手势向右,页面向左
device(scrollable=True).fling.toEnd()    飞滑到页面最底部


device(scrollable=True).scroll(steps=100)   滑动滚动条 距离为100
device(scrollable=True).scroll.horiz.forward(steps=100)  手势向左 页面向右
device(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000) 手势向右 页面向左
device(scrollable=True).scroll.toEnd()  滑动到末尾
device(scrollable=True).scroll.to(text="Security")  scroll 向前垂直,直到出现指定ui object 

device.swipe(500,500,100,500)
"""
swipe 平滑 
    第一种方式:需要传入四个参数
        startX:起始X坐标
        startY:起始Y坐标
        endX:结束X坐标
        endY:结束Y坐标
   """

"""
    第二种方式:需要传入两个参数
        direction(滑动的方向) : up、down、left、right
        scale(滑动的百分比)
"""
device.swipe_ext('left',scale=0.9)


"""
    第三种方式:先进行元素定位 再滑动
        direction(滑动的方向) : up、down、left、right
        steps(滑动的速度) ms
        d.swipe(sx, sy, ex, ey, duration=0.5)
"""
e = device(text='appname')
e.swipe('left',steps=100)

拖拽操作

d.drag(sx, sy, ex, ey, duration=0.5)

附录

#设置每次点击UI后再次单击之间延迟1.5秒
d.click_post_delay = 1.5
#设置默认元素等待超时(秒)
d.wait_timeout = 20








d.info
#得出设备链接信息
print(d.window_size())
#获取屏幕大小
print(d.current_app())
#获取当前应用的信息
print(d.serial)
#获取设备序列号
print(d.wlan_ip)
#获取WIFI IP
print(d.device_info)
#获取详细的设备信息







#打开/关闭屏幕
d.screen_on() 
#开启屏幕
d.screen_off() 
#关闭屏幕
d.info.get("screen") 
#获取屏幕开/关状态
#android>=4.4
d.press("home") 
#按下home键
d.press("back") 
#按下back键
d.press(0*07,0*02) 
#按下编码

'''支持按键模式'''
home
#主页按钮
back
#返回
left
#左
right
#右
up
#上
down
#下
center
#回车
menu
#菜单
search
#搜索
enter
#输入
delete ( or del)
#删除
recent (recent apps)
#打开最近项目
volume_up
#音量+
volume_down
#音量—
volume_mute
#静音
camera
#相机
power
#电源键










d.unlock()
#解锁屏幕
d.click(X,Y)
#点击屏幕坐标
d.long_click(x,y)
#长按屏幕
d.long_click(x,y,1)
#长按屏幕1s,默认是0.5,可自行配置
d.swipe(sx, sy, ex, ey)
#根据坐标滑动
d.swipe(sx, sy, ex, ey,1)
#根据坐标滑动,1代表滑动速度,默认0.5
d.drag(sx, sy, ex, ey)
#根据坐标拖动,适用于结算和滑块处理
d.drag(sx, sy, ex, ey, 1)
#根据坐标拖动,拖动时长1s,默认0.5


#截图
d.screenshot('1.jpg')
#截图保存在本地,文件名为1.jpg
#想获取其他格式的需要安装 pillow、numpy和cv2等库,具体不累述
d.open_notification()
#打开通知
d.open_quick_settings()
#打开快速设置
d.freeze_rotation() 
# 冻结旋转
d.freeze_rotation(False) 
# 开启旋转










'''检查特定的UI对象是否存在'''
d(text="Settings").exists 
# 返回布尔值,如果存在则为True,否则为False
d.exists(text="Settings") 
# 另一种写法
# 高级用法
d(text="Settings").exists(timeout=3) 
# 等待'Settings'在3秒钟出现
 d(text="Settings").info
# 获取特定UI对象的信息

'''获取/设置/清除可编辑字段的文本(例如EditText小部件)'''
d(text="Settings").get_text() 
#得到文本小部件
d(text="Settings").set_text("My text...") 
#设置文本
d(text="Settings").clear_text() 
#清除文本
d(text="Settings").center()
# 获取Widget中心点
#d(text="Settings").center(offset=(0, 0)) # 基准位置左前










d.push('1.txt','sdcard/downloacd')
#推送到文件下
d.push('1.txt','sdcard/downloacd/2.txt')
#推送并重命名到文件夹下
with open("foo.txt", 'rb') as f:
 d.push(f, "/sdcard/")
 #push fileobj
d.push("1.sh", "/data/local/tmp/", mode=0o755)
#推送并修改文件模式,在Python中表示八进制的友好方法默认0o755,文件权限设置
d.pull("/sdcard/1.txt", "1.txt")
#从设备侧拉取文件


'''定位方法'''
#text定位单击
d(text="Settings").click()
d(text="Settings", className="android.widget.TextView").click()
 
#resourceId定位单击
d(resourceId="com.ruguoapp.jike:id/tv_title", className="android.widget.TextView").click() 
 
#description定位单击
d(description="确定").click()
d(description="确定", className="android.widget.TextView").click()
 
#className定位单击
d(className="android.widget.TextView").click()
 
#xpath定位单击
d.xpath("//android.widget.FrameLayout[@index='0']/android.widget.LinearLayout[@index='0']").click()
 
#坐标单击
d.click(182, 1264)
















'''常用方法'''
# 等待10s
d.xpath("//android.widget.TextView").wait(10.0)
# 找到并单击
d.xpath("//*[@content-desc='分享']").click()
# 检查是否存在
if d.xpath("//android.widget.TextView[contains(@text, 'Se')]").exists:
 print("exists")
# 获取所有文本视图文本、属性和中心点
for elem in d.xpath("//android.widget.TextView").all():
 print("Text:", elem.text) 
#获取视图文本
for elem in d.xpath("//android.widget.TextView").all():
 print("Attrib:", elem.attrib)
#获取属性和中心点
#返回: (100, 200)
for elem in d.xpath("//android.widget.TextView").all():
 print("Position:", elem.center())
 
'''xpath常见用法'''
# 所有元素
//*
 
# resource-id包含login字符
//*[contains(@resource-id, 'login')]
 
# 按钮包含账号或帐号
//android.widget.Button[contains(@text, '账号') or contains(@text, '帐号')]
 
# 所有ImageView中的第二个
(//android.widget.ImageView)[2]
 
# 所有ImageView中的最后一个
(//android.widget.ImageView)[last()]
 
# className包含ImageView
//*[contains(name(), "ImageView")]
# 等待10s
d.xpath("//android.widget.TextView").wait(10.0)

# 找到并单击
d.xpath("//*[@content-desc='分享']").click()

# 检查是否存在
if d.xpath("//android.widget.TextView[contains(@text, 'Se')]").exists:
 print("exists")
 
# 获取所有文本视图文本、属性和中心点
for elem in d.xpath("//android.widget.TextView").all():
 print("Text:", elem.text)
 
#获取视图文本
for elem in d.xpath("//android.widget.TextView").all():
 print("Attrib:", elem.attrib)
 
#获取属性和中心点
#返回: (100, 200)
for elem in d.xpath("//android.widget.TextView").all():
 print("Position:", elem.center())


  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

像风一样的男人@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值