python web分布式_使用pytest-xdist实现分布式WEB自动化测试

前言

pytest-xdist是一款优秀的分布式测试插件,它可以实现进程级别的并发,也可以实现类似于master-worker主从分布式测试。目前中文网站对于进程级别的并发介绍的比较多,对于主从分布式测试的资料少之又少。经过反复的实践,对于主从分布式环境的部署和运行有了一定的认知,因此,在本文中将着重介绍主从分布式测试,对于进程并发只做简单的介绍

进程并发

使用pytest命令

pytest -s -n 2 #-n 后面跟核数,如果你的CPU是4核的,那么2表示使用2个核来并发2个进程执行测试

pytest -s -n auto #auto会自动检测你的CPU核数,如果是4核,将并发4个进程

获取安装包

这里面有一些Linux下的安装包,还有我自己用来练手的demo项目WEB_AutoTest

链接:https://pan.baidu.com/s/14vnqtQufXr2Jj1HuACJa9A

提取码:bgdp

其他资料没有准备,因此在开始试验前需要自行安装 pytest,pytest-html,pytest-xdist,selenium

项目介绍

项目结构

WEB_AutoTest

|--test_cases

|--__init__.py

|--test_caculate.py

|--search.py

|--pytest.ini

项目介绍

test_caculate.py是让python自己不停的做次方运算,这是试水项目,不建议一上来就执行web自动化,先搞个demo试试,能运行起来再搭建web自动化环境

# test_caculate.py

import pytest

@pytest.mark.parametrize("n", list(range(50000)))

def test_baidu(n):

a = 2 ** 32

print(f"the baidui-{n}.")

@pytest.mark.parametrize("n", list(range(50000)))

def test_sina(n):

b = 4 ** 32

print(f"the sina-{n}")

search.py的作用是使用无头浏览器不停的打开百度,然后输入关键字,查找网页响应的元素,最后做断言。当test_caculate.py通过之后,可以将其名字更改为test_search.py,将前者改成caculate.py,这样就只会运行web自动化测试

# search.py

from selenium import webdriver

import pytest

@pytest.mark.parametrize("n", list(range(100)))

def test_baidu(n):

# 创建chrome参数对象

options = webdriver.ChromeOptions()

options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在的报错

# options.add_argument('window-size=1600x900') # 指定浏览器分辨率

options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug

options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面

options.add_argument('blink-settings=imagesEnabled=false') # 不加载图片, 提升速度

options.add_argument('--headless') # 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败

driver = webdriver.Chrome(options=options)

driver.get('http://www.baidu.com')

title = driver.title

url = driver.current_url

#输入百度

driver.find_element_by_id("kw").send_keys("百度")

elements = driver.find_elements_by_xpath("//h3//em")

for element in elements:

assert element.text == "百度"

#点击百度一下

driver.find_element_by_id("su").click()

assert title == "百度一下,你就知道"

assert url == "https://www.baidu.com/"

assert type(n) == int

driver.quit()

pytest.ini是一个配置文件,稍后会说明其作用

# pytest.ini

[pytest]

#addopts = --tx socket=192.168.0.109:8888

Windows + Linux主从分布式

系统环境

一开始,我选择了本机Windows做master,虚拟机Centos7做worker1,同时还克隆了一台Centos7作为worker2。有关的环境版本如下:

角色

系统

Python版本

ip

master

Windows7

v3.7.3

192.168.0.101

worker1

Centos7.6

v3.8.0

192.168.0.109

worker2

Centos7.6

v3.8.0

192.168.0.126

同步测试用例并运行

既然要做主从分布式,那么就需要master将测试用例同步给worker。在官网上有两种同步方式:通过远程的SSH账号和通过远程的socket服务。前者我琢磨了比较久,发现怎么试都不成功,于是就直接试后者,后者在官网上的介绍基本能让人看懂:

基本上分为两步:

1.将socketserver.py文件上传到你的服务器,然后这样运行:

python socketserver.py

socketserver.py的文件在我分享的安装包里有,只需下载下来,通过rz命令上传到你的服务器上。我放在了/opt目录下,随便放在哪个目录都行,只要你记得路径就行。接着运行socketserver.py,socket服务就启动了,开始监听8888端口

2.然后在本机(Windows)上运行同步命令

pytest -d --tx socket=192.168.0.109:8888 --tx socket=192.168.0.126:8888 --rsyncdir test_cases test_cases

在工程目录下打开命令行运行。一开始还是好的,没多久Centos7上的socket服务就挂了

截两张socket服务挂了的图

worker1

worker2

有个细节值得注意pytest -d --tx socket=xxxx --rsyncdir xxxx xxxx,这个命令在同步完之后,会自动收集用例并执行。虽然执行的过程挂了,但用例确实同步成功了。就在下图的pyexecnetcache目录下

关于这个服务挂了的问题,github上已经提了一些issue:

With different python versions rsync can hangs on

pytest hangs indefinitely after completing tests in parallel

通过对第一个问题的查看,发现是由于Python版本不一致导致的。接着我更新了两台Centos7上的版本,将它们都改为Python v3.7.7,发现还是会报同样的错误。然后我设想,可以再克隆一台虚拟机,三台Centos7,一个master,两个slave,这样行不行呢?

三台Linux主从分布式

系统环境

这里的Python版本无论是v3.7.7还是v3.8.0都行,只要一致就可以

角色

系统

Python版本

ip

master

Centos7.6

v3.8.0

192.168.0.109

worker1

Centos7.6

v3.8.0

192.168.0.126

worker2

Centos7.6

v3.8.0

192.168.0.136

分布式运行

重新运行之前,注意将项目上传到master上

在worker1和worker2分别运行socket.server

接着进入项目目录WEB_AutoTest,开始执行同步命令

pytest -d --tx socket=192.168.0.126:8888 --tx socket=192.168.0.136:8888 --rsyncdir test_cases test_cases

这次正常了,我们可以看到这些运行截图

master

worker1

worker2

运行结束之后,发现总共运行用例100000条,耗时8min52s。其中,worker1运行了47540条,约占47%,耗时8min41s,worker2运行了52460条,约占52%,耗时8min40s

master

worker1

worker2

单进程运行

我现在使用master单独运行这100000条用例,看看效果

可以看到运行100000条用例,master单进程跑只花了4min24s

多进程运行

如果我给master分配4核,跑2个进程和跑4个进程呢?

2个进程

4个进程

计算次方耗时对比

可以看出,计算型的用例,好像是CPU核数也多,时间越慢。另外分布式的作用好像也不大

环境

核数

用例数量

耗时

备注

Centos7主从分布式

1

100000

8min52s

1 Centos7 master + 2 Centos7 worker

Centos7单进程

1

100000

4min22s

Centos7双进程并发

2

100000

8min38s

Centos7四进程并发

4

100000

11min09s

WEB自动化分布式

安装goole-chrome-stable

将安装包内的google-chrome-stable_current_x86_64.rpm上传到/opt目录下,使用yum安装

yum install ./google-chrome-stable_current_x86_64.rpm

安装成功后,可以使用下面的命令来查看chrome版本

[root@localhost opt]# google-chrome --version

Google Chrome 81.0.4044.122

安装chromedriver

将安装包内的chromedriver_linux64.zip上传到服务器,解压后将它放在/opt/Python-3.8.0/bin目录下,这个是python可执行文件所在的目录,已经配置环境变量了

同样可以使用命令查看chromedriver对应的版本,这个版本和chrome版本一定要对应好

[root@localhost opt]# chromedriver --version

ChromeDriver 81.0.4044.69 (6813546031a4bc83f717a2ef7cd4ac6ec1199132-refs/branch-heads/4044@{#776})

注意:以上说的chrome和chromedriver,三台机器都需要安装

修改模块名

要运行WEB自动化了,不希望执行次方运算,可以使用mv命令重命名下模块名

在一切就绪前,先在本地跑个简单的程序试试水,建议把test_search.py中的参数化改成1次,直接在master运行,看配置的环境有没有问题

正常情况下,运行完应该断言成功

分布式运行

在试验之前,建议把test_search.py的参数化运行次数改成原来的100

方法和前面一样,启动worker上的socket服务后,使用命令

pytest -d --tx socket=192.168.0.126:8888 --tx socket=192.168.0.136:8888 --rsyncdir test_cases test_cases

可以看到,总共运行100条用例,总耗时2min42s,其中worker1运行用例52条,耗时2min42s,worker2运行用例28条,耗时2min40s

master

worker1

worker2

单进程运行

运行用例100条,耗时4min57s

多进程运行

2个进程

100条用例耗时2min50s

4个进程

4个进程甚至更快,总耗时才1min40s

不过还要考虑一种情况,就是分布式有个同步用例的过程,现在我把同步用例的过程去掉,试试分布式的时间。看样子也要2min32s

WEB运行耗时对比

环境

核数

用例数量

耗时

备注

Centos7主从分布式

1

100

2min42s

1 Centos7 master + 2 Centos7 worker

Centos7单进程

1

100

4min57s

Centos7双进程并发

2

100

2min50s

Centos7四进程并发

4

100

1min40s

Centos7主从分布式不同步

1

100

2min32s

配置文件

和pytest的pytest.ini一样,你可以在pytest.ini中做一些配置,比如想要三个进程执行就可以使用配置

[pytest]

addopts = -n3

如果之前已经同步了一次测试用例,这次想要直接运行,但又不想跟特别长的--tx怎么办

[pytest]

addopts = --tx socket=192.168.0.126:8888 --tx=socket=192.168.0.136:8888

这样配置之后,你可以根据情况来选择运行

pytest --dist=each

或者

pytest --dist=load

each模式和load模式

这两个模式的解释最后才找到,官网藏得比较隐蔽。你可以点击这里查看-->dist的模式

--dist=each:master将所有的测试用例都分发到各个worker上,相当于worker1执行所有的100条用例,worker2执行所有的100条用例。运行完master上显示的总用例个数是200条

--dist=load:master先将25%的用例以循环的方式分发给每个worker,剩下的用例等worker执行完之后再分发。有点nginx负载均衡的感觉,worker负载过高,master会将其负载降低一些,让其他worker分摊一点。这种模式运行的总用例个数是100条,worker1和worker2运行的用例数不定,有可能各是50条,有可能一个是48条,一个是52条。就像我们之前看到的那样

使用pytest -d --tx socket=xxxx rsyncdir xxxx xxxx这种同步方式运行,默认的是load模式

APP自动化分布式设想

WEB自动化之所以简单,是因为只要chromedriver和chrome版本一致,问题应该不是很大。但APP就不同了,APP涉及到的东西较多,首先必须要有真机或者模拟器,然后还要启动appium服务端,在脚本中将desired_caps(比如platformName,packageName,activityName,systemVersion等)传递给appium服务端,再由服务端返回driver来操作客户端

因此APP自动化也要保证环境的一致性,即所装的APP版本,模拟器系统版本、appium的端口号都要一致,因为都是一套代码推送到不同的worker。可以像之前那样继续使用docker,注意的是两个worker的appium容器的docker_name必须一样,这样才可以在脚本里使用docker docker_name的方式启动appium服务

还有一个问题是,如果master和worker都是Centos7,就要考虑模拟器怎么和远程的worker连起来,之前尝试过通过tcpip来连,是可以成功的。这个tcpip端口号可以设置不同,因为desired_caps里对这个deviceName没要求。这么来看,APP自动化也是具有可行性的

事实上,分布式测试对用例的独立性要求很高,尽量避免不必要的依赖,这也是UI自动化设计的原则

参考文章

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值