琦鱼的uiautomator2自动化测试学习笔记

uiautomator2 对比 Appium

Appium:相对复杂,要安装的软件多,程序需要配置启动参数

Appium 适用场景:跨平台,标准化

uiautomator2:相对简单,适合入门学习

环境搭建

Python 3

Pycharm 社区版

一台安卓设备(可以是安卓模拟器)

入门操作

入门示例程序代码如下:

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2
# 连接设备 (通过设备序列号,测试设备只有一台时序列号可以为空)
device = uiout2.connect()
# 打开被测试的应用程序
device(text='QQ').click()

adb 安装

adb 全称安卓调试桥,调试安卓设备必备工具

下载 adb 调试工具

adb 安装与配置

连接设备

连接设备:

查看设备序列号:使用命令行命令 adb devices

通过设备序列号,测试设备只有一台设备时序列号可以为空

通过设备的IP地址进行连接时,需要打开设备的开发者模式网络调试开关

相关代码示例如下:

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2
# 连接设备 设备序列号:33QY6790
device = uiout2.connect('33QY6790')
# 连接设备 设备:http://192.168.0.12
device = uiout2.connect('http://192.168.0.12')
# 连接设备 设备:http://192.168.0.13:3321
device = uiout2.connect('http://192.168.0.13:3321')
# 连接设备 设备IP:192.168.0.13
device = uiout2.connect_wifi('192.168.0.13')

应用的安装与卸载

安装应用

准备一个应用安装包地址,可以是网络地址也可以是本地地址

# 安装 应用
url = 'https://p.baifi.com/89uui/qiyu/qq.apk'
device.app_install(url)

获取应用包名

获取应用包名前提需要打开应用,返回内容里 package 后面的是包名

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2
# 连接设备 adb 通过设备序列号: 33QY6790
device = uiout2.connect(r'33QY6790')
# 打开应用
device(text='QQ').click()
# 获取当前屏幕上正在运行应用的包名
print(device.app_current())
# 获取所有正在运行应用的包名
print(device.app_list_running())

通过 adb 指令获取应用包名,前提需要打开应用

两条命令结果一样

adb shell dumpsys activity | find "mFocusedActivity"

adb shell dumpsys activity top | findstr ACTIVITY

通过 aapt 指令获取应用包名,前提需要配置 aapt 环境变量

解析得到应用包名,file.apk 为文件或者包含文件的路径

aapt dump badging file.apk

卸载应用

调用方法 传入应用包名

device.app_uninstall()

应用的启动和关闭

应用的启动

前提是需要获取应用包名,通过包名启动应用

device.app_start()

应用的关闭

前提是需要获取应用包名,通过包名启动应用

device.app_stop()

清楚应用数据

清空输入框等控件数据,需要传入应用包名

device.app_clear()

设备操作

获取设备信息

获取设备相关信息,返回为字典类型 两行方法执行结果不太一样,请尝试一下

device.info
device.device_info

获取设备屏幕大小

获取设备屏幕大小,方便定位元素

返回为元组类型

device.window_size()

设备截屏

在设备上截取屏幕信息,传入参数为文件名:1.png ;也可以传入保存路径

device.screenshot('1.png')
device.screenshot(r'c:\1.png')

推送文件到设备

从电脑把文件传送到目标设备,传入第一个参数为电脑文件保存路径;第二个参数为设备存放文件地址 可能遇到权限问题

device.push(r'c:\1.xls', '/data/')

从设备拉取文件到电脑

把设备文件传送到电脑,传入第一个参数为设备存放文件地址;第二个参数为电脑文件保存路径 可能遇到权限问题

device.pull('/data/1.xls', r'c:\1.xls')

设备按键操作

模拟设备按键操作,不需要物理按键支持,也可以使用数字

参考按键对应数字

# 设备亮屏
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 ( or del)")
# 最近浏览应用
device.press("recent (recent apps)")
# 拍照
device.press("camera")
# 电源
device.press("power")

相关示例代码:

# 音量加
device.press("volume_up")
# 音量减
device.press("volume_down")
# 静音
device.press("volume_mute")
# 最近浏览应用
device.press('recent')
# 电源键
device.press('power')

元素定位

通过某一些特征来定位元素,辅助元素定位工具 weditor

python 3 在安装 weditor 时 报错请参考1 报错请参考2

安卓官方有一个工具 uiautomatorviewer ,安卓 sdk (sdk/tools/uiautomatorviewer.bat)自带

推荐使用 weditor

应用页面是用 xml 文件构成

# 安装 weditor
pip install weditor
# 查看已经安装的库
pip list
# 运行weditor
weditor
# 通过 text 文本定位 进入应用
device(text='').click()
# 通过 resourceId 定位
device(resourceId="").click()
# 通过 textContains (text 通过文本内容包含内容 定位元素,要确保唯一性)
device(textContains="").click()
# 通过 className 文本定位
device(className='').click()
# device(参数1,参数2).click() 组合条件
device(className='', text='').click()
# 当通过 特征 定位的元素有多个时,可以通过 索引(从0开始)选择已经定位的元素
device(resourceId="", instance=2).click()
# 通过 层级关系定位
device(resourceId='').child(resourceId='').click()
# 通过相对位置定位元素  速度较慢
button = device(resourceId='')
button.left().click()

元素构成

1.控件名称

2.控件属性

3.子控件

根据层级关系定位元素

  1. 上下级关系 (包含与被包含)

  2. 同胞关系 (同级关系)

  3. 相对位置 (左右上下)

设备应用操作

点击

首先需要连接设备

# 通过 元素特征定位来点击
device(resourceId='').click()
# 通过 元素坐标来点击
device.click(x, y)
# 通过 元素位置百分比来点击
device.click(w, h)

滑动操作

在设备屏幕上进行滑动操作

# 4个参数:开始坐标x,y;结束坐标x,y
device.swipe(startx, starty, endx, endy)
# 2个参数:滑动方向;滑动幅度
device.swipe('', scale=)
# 通过元素定位滑动 2个参数:滑动方向;滑动时长
device.swipe('', steps=)

内容输入和清空

在设备上模拟输入和清空输入内容

# 定位输入框 输入内容
device(resourceId='').send_keys('')
# 清空输入内容
device(resourceId='').clear_text()

获取设备截屏

获取设备屏幕信息图片,图片处理库 pillow 以及 cv2

# 获取设备屏幕信息图片 默认保存在当前程序文件夹
device.screenshot('')
# 获取设备屏幕信息图片 可以接入图片处理库 pillow ,需要导入库文件
image = device.screenshot()
# 保存图片
image.save("")
# 图片模糊处理 并保存
image.filter(ImageFilter.BLUR).save()
# 图片大小处理 并保存
image.resize((w, h)).save()

元素等待

代码执行快,设备相应较慢,所以需要等待

# 普通等待 (浪费时间)
time.sleep()
# 等应用加载完成启动 默认20秒内,超时报错(智能等待)
device.app_start('', wait=True)
# 修改默认wait值 (这一行应该在上面)
device.wait_timeout = 
# 修改默认wait值 (这一行应该在上面  全局设置)
device.implicitly_wait()
# 等待页面加载完成
device.wait_activity()
# 等待元素出现 返回布尔值(True/False)
device(text='').wait()
# 等待元素消失 返回布尔值(True/False)
device(text='').wait_gone()
# 判断等待元素是否存在
device(text='').exist()
# 可以通过 timeout 设置等待时间 (单独设置)
device(resourceId="").click(timeout=)
# 输入等待 通过 timeout 设置等待时间 (单独设置)
device(resourceId="").set_text(timeout=)
# 清空等待 通过 timeout 设置等待时间 (单独设置)
device(resourceId="").clear_text(timeout=)

实际案例及源码

测试一个应用的登录功能

  1. 测试用例:制定合适的测试参数及相关操作方案
  2. 代码编写:编写测试代码
  3. 断言:写测试总结

基本源码

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2
# 连接设备 (通过设备序列号,测试设备只有一台时序列号可以为空)
device = uiout2.connect(r'33QY6790')
# 启动被测试的应用程序
device.app_start('com.yunyao.yuncc', wait=True)
# 清空应用数据
device.app_clear('com.yunyao.yuncc')
# 点击图床
device(resourceId="com.yunyao.yuncc:id/network_tuch").click()
#判断登录按钮是否存在
button = device(resourceId="com.yunyao.yuncc:id/go_login")
if button.exists():
    # 登录
    button.click()
    device(resourceId="com.yunyao.yuncc:id/et_moble").send_keys('182116000000')
    device(resourceId="com.yunyao.yuncc:id/et_password").send_keys('yunyao33607')
    device(text='登录').click()

# 访问栏目
device(text='蛇年大吉').click()
# 退出应用程序
device.app_stop('com.yunyao.yuncc')

应用执行流程源码

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2

# 编写对应函数
def test_logo_empty_mobile():
    # 连接设备 (通过设备序列号,测试设备只有一台时序列号可以为空)
    device = uiout2.connect(r'33QY6790')
    # 启动被测试的应用程序
    device.app_start('com.yunyao.yunllyu', wait=True)
    # 进入登录页面
    device(resourceId="com.yunyao.yunllyu:id/network_logo").click()
    # 准备登录
    device(resourceId="com.yunyao.yunllyu:id/fragment_logo_lemon_avatar_title").click()
    # 输入用户手机号码
    device(resourceId="com.yunyao.yuncc:id/et_moble").send_keys('')
    # 输入用户密码
    device(resourceId="com.yunyao.yuncc:id/et_password").send_keys('')
    # 点击登录按钮
    device(text='登录').click()
    # 退出应用程序
    device.app_stop()
    # 断言 应用是否提示 手机号码或密码不能为空 测试结果在控制台输出
    assert device.toast.get_message() == '手机号码或密码不能为空'

测试案例运行优化

1.pytest 库的安装

右键选择 pytest 运行测试代码

pip install pytest

2.逻辑代码的封装

# 导入库文件 重命为uiout2
import uiautomator2 as uiout2
# 导入库文件
import pytest

# 登录函数 传入3个参数:设备 用户名 密码
def logo(device, username, passwd):
    device.app_start('com.yunyao.yunllyu', wait=True)
    # 进入登录页面
    device(resourceId="com.yunyao.yunllyu:id/network_logo").click()
    # 准备登录
    device(resourceId="com.yunyao.yunllyu:id/fragment_logo_lemon_avatar_title").click()
    # 输入用户手机号码
    device(resourceId="com.yunyao.yuncc:id/et_moble").send_keys(username)
    # 输入用户密码
    device(resourceId="com.yunyao.yuncc:id/et_password").send_keys(passwd)
    # 点击登录按钮
    device(text='登录').click()
    # 退出应用程序
    device.app_stop()

# 测试登录 函数
def test_logo_empty_mobile():
    # 连接设备 (通过设备序列号,测试设备只有一台时序列号可以为空)
    device = uiout2.connect(r'33QY6790')
    # 启动被测试的应用程序
    device.app_start('com.yunyao.yunllyu', wait=True)
    # 调用登录函数 并传入参数
    logo(device, '', '')
    # 断言 应用是否提示 手机号码或密码不能为空 测试结果在控制台输出
    assert device.toast.get_message() == '手机号码或密码不能为空'
# 使用 pytest 进行测试
if __name__ == '__main':
    pytest.main()

3.mark 功能

给测试用例 打标签 在测试函数上面打标签

# @pytest.mark.标签名
@pytest.mark.logo_test
# 标签的使用
pytest.main(['-m logo_test'])

生成测试报告

1.安装库 pytest-html

pip install pytest-html

2.生成测试报告

# 测试报告文件名:testlogo.html  默认生成在当前文件夹
if __name__ == '__main':
    pytest.main(['-m logo_test', '--html=testlogo.html'])

3.查看测试报告

测试报告默认生成在当前文件夹,选择测试报告 .html 文件用电脑浏览器打开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云瑶琦鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值