前一段时间,用python+夜神实现了基于模拟器的自动化测试。链接见:
https://blog.csdn.net/saint_228/article/details/84889017
最近想把自动化在真机上实现。所以捣鼓了几天,弄了个简易版测试架构,开销不多,效果不错,在此分享给大家。
2019-5-21 增补:项目实例代码下载地址: https://download.csdn.net/download/saint_228/11169391
2019-5-30 增补:CSDN上更新版本不便,源码放到git :https://github.com/saint228/DreamMultiDevices
我们公司提供了5部测试手机,但同一台PC机不可能同时接入这么多设备。所以,采购一个带电源的USBHub是必须的开销。某宝上百来块入手了一个。
建议再买个机架,看起来更专业一点。合计开销不到200。
我期望的自动化测试能在每天的dailybuild之后自动进行apk的下载、安装、运行测试脚本并发送邮件,同时还能在网页上实时观察测试进展。综合这些需求,我采用的是Linux+STF+Pyhon的方式。如果不需要使用到STF,那在Windows平台上也是可以行得通的。
使用的是CentOS7,网上安装教程一大堆,这里不赘述。
CentOS自带的Python是2.7版本,不建议使用。
[qatest@127 ~]$ python
Python 2.7.5 (default, Apr 11 2018, 07:36:10)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
默认的Python千万别动,很多其他模块会依赖于它。
我们需要重新安装一个Python3的版本,目前的Python3的最高版本是3.7,但考虑到与Poco的兼容,建议下载Python3.6。
[root@127 qatest]# yum install python36
(PS:实际上我首先一开始并未下载3.6,而是直接下载的3.7版本,但使用CentOS默认源下载的Poco、Airtest等其他库对3.7并不兼容。如果手动更换源,应该也是可以用3.7版本的。)
之后记得给python3.6设一个环境变量,方便之后直接调用。
[root@127 qatest]# python36
Python 3.6.6 (default, Jan 26 2019, 16:53:05)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
然后装pip
[root@127 qatest]# yum install python36-pip
pip装好以后用pip去安装脚本会用到的若干库。特别注意一点,python3.6并不与最新的airtest以及pocoui兼容。要安装特定版本。
[root@127 qatest]# pip3.6 install airtest==1.0.24
[root@127 qatest]# pip3.6 install pocoui==1.0.70
[root@127 qatest]# pip install multiprocessing
...
我的整个脚本里还用到了traceback(抓取异常)、smtplib(邮件发送)、xlrd/xlwt(Excel表格处理)等库,酌情添加。
STF是开源的一个远程网页调试手机的框架。
其本身的安装非常麻烦,推荐使用docker容器来安装。
首先安装docker。
[root@127 qatest]# yum install -y yum-utils device-mapper-persistent-data lvm2 && yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo -y&&yum -y install docker-ce-18.06.3.ce-3.el7&&systemctl start docker &&systemctl status docker
输入docker version,看到客户端和服务端的信息,就说明安装成功。
[root@127 qatest]# docker version
Client:
Version: 18.06.3-ce
API version: 1.38
Go version: go1.10.3
Git commit: d7080c1
Built: Wed Feb 20 02:26:51 2019
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.06.3-ce
API version: 1.38 (minimum version 1.12)
Go version: go1.10.3
Git commit: d7080c1
Built: Wed Feb 20 02:28:17 2019
OS/Arch: linux/amd64
Experimental: false
docker安装好以后再pull一下stf需要的几个镜像
sudo docker pull openstf/stf:latest # STF镜像
sudo docker pull rethinkdb:latest # rethinkdb 镜像
sudo docker pull openstf/ambassador:latest
sudo docker pull nginx # nginx 镜像
然后加载容器
docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
docker run -d --name stf --net host openstf/stf stf local --public-ip 127.0.0.1
本来stf的推荐流程里还要装一个adb,但adb在airtest里已经自带,所以就没必要重复安装了。直接adb start-server即可。如果无法直接执行,就添加一下环境变量。
然后启动STF所需的rethinkdb、adb以及STF本身,注意rethinkdb和adb需要在STF启动之前启动。
docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
docker run -d --name stf --net host openstf/stf stf local --public-ip 127.0.0.1
我这里ip设定的本地访问,需要根据实际情况修改。然后在浏览器输入对应ip:7100即可访问。
测试的脚本主要是调用python的airtest库来进行控件操作。
为了同步多部手机同时运作,这里需要使用多进程来编写脚本。
(PS:python的多线程无法满足我的需求,一开始我的脚本用多线程来实现,结果是每部手机逐次运行脚本,并不能达到同步运行的效果)
#将设备id存入deviceslist
deviceslist = cc8c4f82,6c176579,P4M0215107001638,99fa1f38,
packName = 包名
if __name__ == '__main__':
try:
pool = multiprocessing.Pool(processes = len(deviceslist))
startTime = time.localtime(time.time())
#根据设备数创建相应进程
for i in range(0, len(deviceslist)):
results.append(pool.apply_async(Main, (i, startTime, )))
pool.close()
pool.join()
except AirtestError as ae:
print(startTime, "System", "进程池 发生错误:\n" )
然后在Main函数里,进行测试脚本的调用
def Main(processNo, startTime):
#进程与设备是一一对应关系
devices = deviceslist[processNo]
print(startTime, "进程: " + str(processNo) + " 设备号:" + devices)
#调用PushApk2Device函数,推送apk到手机
PushApk2Devices(devices, packName, startTime)
time.sleep(3)
print(startTime, "System", devices + " 脚本开始")
testResult = RunTestCase(devices, startTime) # 开始调用脚本
中间调用到的PushApk2Device函数的作用是将待测试的apk推送到设备上,相关代码如下:
def PushApk2Devices( devices, packName, startTime):
srcpath=GetPath()
try:
print(startTime, "System", devices + " 开始安装新版本")
#由于设备均未root,所以采用-r方式覆盖安装,可以绕过安装apk时的各个权限确认
result = os.system("adb -s " + devices + " install -r " + srcpath)
print(startTime, "System", devices + " 安装新版本: " + str(result))
except Exception as e:
print(startTime, "System", devices + " 安装新包 发生错误:\n" )
sys.exit()
#GetPath方法获取源包的路径。由于我们项目dailybuild的服务器是Windows系统,所以在linux上取包需要提前将对应路径挂载到/mnt/apkPath 目录下:
file_path = "/mnt/apkPath/"
def GetPath():
dir_list = os.listdir(file_path)
#getmtime方法按时间顺序,获取目录最新一个文件
filelist = sorted(dir_list, key=lambda x: os.path.getmtime(os.path.join(file_path, x)))
lastest_release = filelist[-1]
#拼接路径与文件
srcpath = os.path.join(file_path, lastest_release)
return srcpath
另一个RunTestCase则是开始进行实际测试的函数
def RunTestCase(devices, startTime):
try:
print(startTime, devices, "创建设备连接")
#手动指定连接,这一步很重要
connect_device("Android:///" + devices)
print(startTime, devices, "设备连接成功")
time.sleep(15)
#初始化设备
auto_setup(__file__)
print(startTime, devices, "启动App")
start_app(packName, activity = None)
print(startTime, devices, "App启动完成")
time.sleep(15)
#初始化poco
poco = UnityPoco()
print(startTime, devices, "初始化设备完成")
except AirtestError as ae:
printstartTime, devices, "初始化设备 Airtest发生错误:\n" )
之后就可以自由自在地运行自己写的各种测试脚本了。
脚本执行时,也可以通过STF,远程观察测试程序实时的运行情况。
liunx:
16. liunx系统中许多程序需要python2.7支持。安装python3后需要将python3设置为默认,并在安装pip后将其指向python3
17. 部分系统(比如:ubnutu)pip安装的python库会被安置到dist-packages,而python的第三方库路径在site-packages中,需要通过配置.pth文件重定向读取路径
18. 注意adb工具、Log文件夹等路径的权限
19. 定时任务crontab文件的配置完成后需要等待3-5分钟,cron服务才会自动加载配置
手机配置:
20. 小米系统的手机需要登录小米账户后在开发者选项中开启“USB调试(安全设置)”,不然无法进行模拟点击测操作