1. 背景
项目测试过程中经常需要在手机端体验语音产品的识别效果和稳定性,识别效果与手机硬件强相关无法抛开硬件影响。因此开发了一套基于 uiautomator2+python UI 自动化工具,可以实现在电脑端控制手机 demo 开始收音+播放待测音频+保存识别结果的 APP 自动化效果测试工具。
2. uiautomator2 安装及介绍
uiautomator2 是一个自动化测试开源工具,仅支持 Android 平台的原生应用测试。它本来是 Google 提供的一个自动化测试的 Java 库,后来发展了 python-uiautomator2,封装了谷歌自带的 uiautomator 测试框架,提供便利的 python 接口,用它可以很便捷的编写 python 脚本来实现 app 的自动化测试。uiautomator2 提供了点击、长按、输入文本、滑动、拖拽、截屏等方法,能够模拟用户的各种动作。用户可以通过控件的 id 或 text 等属性,定位到控件,从而对控件实施上述操作。
2.1 环境搭建
2.1.1 安装 adb
安装adb并使手机与电脑连接(具体安装自行百度)。
adb devices 查看连接设备。
复制代码
2.1.2 安装 uiautomator2
pip install --pre -U uiautomator2
复制代码
2.1.3 设备安装 atx-agent
python -m uiautomator2 init (安装包含httprpc服务的apk到手机)
复制代码
2.1.4 安装 weditor
基于浏览器技术的 weditor UI 查看器,方便抓取手机上应用的控件。
pip install --pre weditor(安装)
python -m weditor(运行)
复制代码
2.2 atx 主要方法
2.2.1 设备连接
import uiautomator2 as u2
d = u2.connect('192.168.1.169') #通过WIFI
d = u2.connect_usb('123456f') #通过USB(手机的序列号可以通过adb devices获取到,假设序列号是123456f)
复制代码
2.2.2 获取当前包名
cmd 界面输入“uiautomator2 current ”,能获取手机当前界面 APP 的包名、activity 以及 pid 等相关信息,如下:{"package": "com.android.browser", "activity": "com.uc.browser.InnerUCMobile", "pid": 28478 }。
2.2.3 启动/停止 APP
//启动
d.app_start("com.android.browser") #默认的这种方法是先通过atx-agent解析apk包的mainActivity,然后调用am start -n $package/$activity启动
d.app_start("com.android.browser", use_monkey=True) #使用 monkey -p com.example.hello_world -c android.intent.category.LAUNCHER 1 启动,这种方法有个副作用,自动会将手机的旋转锁定给关掉
//停止
d.app_stop("com.android.browser")
d.app_clear('com.android.browser')
复制代码
2.2.4 元素定位方法
d(resourceId="com.smartisanos.clock:id/text_stopwatch").click() #ResourceId定位
d(text="发现").click() #Text定位
d(description="..").click() #Description定位
d(className="android.widget.TextView").click() #ClassName定位
复制代码
2.2.5 控件操作
d.click(x, y) #点击
d.double_click(x, y) #双击
d.double_click(x, y, 0.1) # 两次点击时间间隔0.1秒
d.long_click(x, y) d.long_click(x, y, 0.5) # 点击时间0.5秒,长按
复制代码
2.3 uiautomator2+python UI 自动化测试框架简介
python 端:运行脚本,并向移动设备发送 HTTP 请求。移动设备:移动设备上运行了封装了 uiautomator2 的 HTTP 服务,解析收到的请求,并转化成 uiautomator2 的代码,对被测程序进行相关操作。
3.实战案例
3.1 手机计算器
以下以计算器为例,计算七加八并自动获取计算结果。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import uiautomator2 as u2
import time
if __name__ == '__main__':
d = u2.connect_usb("123456f") # 通过USB连接手机(手机的序列号可以通过adb devices获取到,假设序列号是123456f)
d.app_start("com.coloros.calculator") # 通过包名启动手机计算器(不同手机计算器包名可能不同,需要修改)
d(resourceId="com.coloros.calculator:id/digit_7").click() # resourceId定位法,点击“7”
d(resourceId="com.coloros.calculator:id/op_add").click() # 点击“+”
d(text="8").click() # text定位法,点击“8”
# d(resourceId="com.coloros.calculator:id/eq").click()
d.click(0.829, 0.92) # 坐标定位法,找到“=”的坐标点,点击“=”
d(resourceId="com.coloros.calculator:id/result").get_text() #获取result结果
time.sleep(5)
d.app_stop("com.coloros.calculator") #关闭手机计算器
复制代码
3.2 语音助手识别效果自动化测试
同时控制手机和音箱,配合模拟人与手机助手的语音交互并保存返回的识别结果
控制手机打开语音助手
def openAssistant()
d = u2.connect_usb("手机序列号")
d.app_start("包名", "activity", use_monkey=True) #启动手机语音助手,需要通过语音助手包名启动
d.click(x, y) #通过坐标定位方法,点击语音助手浮球,开启语音助手交互
复制代码
播放测试音频文件
# pcm音频读取
class PcmRead:
def __init__(self, path, sampleRate, sampleSize, channelCount):
self._i_opened_the_file = None
if isinstance(path, str):
f = open(path, 'rb')
self._i_opened_the_file = f
# else, assume it is an open file object already
self._framerate = sampleRate
self._sampwidth = sampleSize
self._nchannels = channelCount
self._nframes = os.path.getsize(path) // (sampleSize * channelCount);
def __del__(self):
self.close()
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def close(self):
file = self._i_opened_the_file
if file:
self._i_opened_the_file = None
file.close()
def getnchannels(self):
return self._nchannels
def getnframes(self):
return self._nframes
def getsampwidth(self):
return self._sampwidth
def getframerate(self):
return self._framerate
def readframes(self, nframes):
size = nframes * self._sampwidth * self._nchannels;
data = self._i_opened_the_file.read(size);
return data
#播放音频文件
def play(audioPath):
if audioPath.endswith(".pcm"):
wf = PcmRead(audioPath, "音频采样率", "采样点大小,只支持2", "音频声道数")
elif audioPath.endswith(".wav"):
wf = wave.open(audioPath, 'rb')
else:
raise ValueError("invalid suffix")
with wf:
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
CHUNK = 1024
data = wf.readframes(CHUNK)
while b'' != data:
stream.write(data)
data = wf.readframes(CHUNK)
stream.stop_stream()
stream.close()
p.terminate()
复制代码
4.可扩展领域
uiautomator2+python UI 自动化测试框架,与 selenium 和 unittest 的 Web UI 自动化测试框架相类似,基于 Android 系统有屏设备的自动化测试解决方案,支持对被测设备的模拟点击、截图、获取返回结果等功能。可用于所有 Android 带屏设备的 APP 测试。
评论