不知道大家有没有遇到这样一种情况,实际工作中,app自动化测试的用例可能是成百上千条的,如果放在一台机器上跑,消耗的时间非常久,那能不能使用分布式的来跑测试用例呢?比如有1000条测试用例,给A机器分配500个,给B机器分配500个,同时去跑,这样耗时就大大减少。刚好pytest-xdist为我们提供了一种可能
什么是pytest-xdist?
pytest-xdist是一款分布式测试插件。它在pytest的基础上做了一些独有的测试执行模式的扩展。比如你有多个CPU或者多台机器,就可以使用它们做一些并行化的测试,并且它还是跨平台的,可以指定不同的python解释器或不同的平台来执行测试
pip install pytest-xdist
01 分布式测试的原理
上面有提到pytest-xdist实现分布式的方式有两种:一种是使用多CPU,一种是使用多台机器。
一般来说对于web自动化测试,使用多核CPU来做分布式比较合适,但对于app自动化测试来说,使用多台机器做分布式比较合适。这里主要介绍后者
pytest-xdist是工作方式是一个master对应多个worker,每个worker会按照master的要求来执行各自的测试集。
基本的执行流程为:
master在测试会话开始的时候会产生一个或多个worker。master和worker之间使用execnet及其网关进行通信。worker可以是本地的,也可以是远程的
worker作为pytest的执行者。在收集完一套完整的测试集后,worker将收集到的测试id发送给不承担执行任务的master
master接收所有节点发送来的结果,同时也会做一些可用性的检查以确保所有的worker都收集到相同的测试集。如果一切正常,它会将测试id列表转换为简单索引列表,每个索引对应着它在原始测试集列表中的位置。这种方案的可行性在于可以节约带宽,由于所有的worker都有相同的测试集列表,所以master可以指派其中一个worker只执行测试索引为3的用例
pytest-xdist有两种模式,each模式和load模式
each模式:
master会将所有的测试任务(这里的测试任务不是测试集,类似于测试指令,也就是上面说的测试索引)发送到每个worker上,每个worker都执行一遍完整的测试集。
举个例子,假如有1000条用例,分为A和B两个worker,那么A和B同时执行1000条用例
load模式:
master会先将25%的测试任务以轮询的方式发送给每个worker,剩下的等到worker执行完后再做分发。同样,有1000条用例,有A和B两个worker,那么先给A分发250个用例,再给B分发250条用例,剩下的500条用例等A和B执行完后再做分发,有可能此时A服务器的压力比较小,那么给A再分260条,B的压力比较大,给B再分240条。类似于负载均衡的概念
02 测试项目
以百度贴吧app为例,可以写简单的4条用例来测试。第一条测试的是欢迎页的滑动功能。如果用户点了同意,后面滑屏,能够正常滑动,点击立即体验,能够正常跳转,说明用例是通过的
第二条测试的是欢迎页点击不同意,能够正常弹出提示,说明用例是通过的
第三条测试搜索,如果用户滑屏后,在主页搜索栏输入关键字,能够搜索到指定的内容,说明用例通过
最后一条测试登录,点击主页“我的”,能够进入到百度账号登录页面,说明用例通过
03 环境准备
在搭建环境上,我准备了三台虚拟机,其中一台作为master,剩下两台作为执行的worker。为了避免不必要的麻烦,三台机器都统一使用python3.8,两台worker上都使用docker安装appium1.17.0,客户端采用两台系统为v7.1.2的夜神模拟器。
具体信息如下表所示:
服务器环境
04 搭建步骤
1、在worker上创建并启动docker容器
在两台worker上执行同样的操作,可以启动一个名为appium的容器
看到这里或许会问,docker里的appium服务是怎么启动的,比较简单,代码可以通过命令行的方式启动appium服务
2、模拟器设置
通过桥接的方式,设置tcpip端口,使得远程服务器可以通过adb连接到模拟器。具体方法是点开右上角的设置,进入系统设置,属性设置,勾选开启网络桥接模式,这时候应该会装一个桥接网卡,然后可以自己设置静态IP。保存后重启就可以了
正常情况下,重启后ip应该会变成静态IP,但是夜神模拟器有个bug,ip还是随机ip,不过这一点不影响后续的操作
接下来设置tcpip端口,通过如下命令设置好后,如果看到有restarting in TCP mode port:6666说明已经设置完成
3、appium远程连接模拟器
在两台worker上分别执行远程连接命令,worker1对应模拟器1,worker2对应模拟器2。这里要主要adb connect 后面跟的是模拟器的实际ip地址加tcpip端口号6666,如果看到connected to ip:端口号,说明已经远程连接成功
4、上传代码
使用命令或工具将代码上传到master上的/opt目录下并解压
main.py是项目测试执行的入口,为了适应分布式执行,我们需要对main.py做一些修改
对最关键的几步做一个说明:
“-d”:
表示分布式参数
"–tx"后面跟着worker服务器的地址
且通过python=/opt/Python-3.8.0/bin/python3.8指定了python版本,通过chdir=/opt/pyexecnetcache指定了worker上同步测试集的目录,也就是master会将测试项目同步worker的该目录下
“–rsyncdir"后面跟”./",
表示将master上当前目录下的所有文件都同步
“TieBa-AutoTest”:
因为同步过去的项目在pyexecnetcache目录下,实际上是/opt/pyexecnetcache/TieBa-AutoTest,如果不加该配置,就进入不到TieBa-AutoTest目录下,由于worker上的pytest执行时是找test_开头的测试用例,所以会找不到测试用例,可以将其理解为cd TieBa-AutoTest
05 分布式执行
在master上执行python3 main.py命令就可以做分布式运行,gw0和gw1分别表示worker1和worker2,[4]表示共有4条测试用例
此时去看worker的/opt目录下,已经同步到了测试项目
再去观察两台模拟器,发现已经开始同步执行了
06 测试报告
测试完成后,观察master上的执行结果信息,4条测试用例耗时不到3分钟,2条通过2条失败。
但是在master上通过allure serve生成预览报告后,发现报告是空的
两台worker上的报告预览展示正常,分别展示它们各自执行用例的报告信息
其原因是pytest-xdist对allure测试报告支持的不友好,各个worker的测试报告信息没有回传,使用pytest-html就没有这个问题。github上有人提出过这个问题。暂时留个“悬念”,下次再讲讲怎么解决这一问题
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取