背景
随着自动化case数量的增长,执行一次耗时也越来越长,目前生产环境大概需要40分钟才能跑完所有case!时间,时间就是生命,需要想办法来提高运行速度。
一般情况下我们会想先优化代码,看看哪边耗时比较长,常规的优化可以分为三个步骤:数据准备, 执行操作,结果检查。
这边数据大多在testcollection直接传递,而结果检查现在大部分的断言并不复杂,因此数据准备,结果检查就不多提了。执行操作,主要是超时时间设置,还有些如减少time.sleep的操作等等。
今天直接上大招:多进程。
多进程运行
pytest本身不支持多进程,需要配合其他组件来完成,常用的pytest-xdist ,pytest-parallel。两者的区别在于pytest-xdist是多进程运行,有几个CPU就可以设置到多大,而pytest-parallel支持多进程和多线程,可以设置N个进程,每个进程M个线程,最后是N * M个线程同时运行。
(以下为未解决登录互斥问题前的数据)
未使用多进程之前
case数 | 时间 | 进程数 | 失败case数 |
---|---|---|---|
143 | 654s | 1 | 0 |
pytest-xdist
case数 | 时间 | 进程数 | 失败case数 |
---|---|---|---|
143 | 254s | 2 | 0 |
143 | 215.23s | 2 | 0 |
pytest-parallel
case数 | 时间 | 进程数 | 每个进程最大线程数 | 失败case数 |
---|---|---|---|---|
143 | 68s | 2 | 4 | 9 |
143 | 83.02s | 2 | 4 | 8 |
143 | 65.75s | 2 | 4 | 7 |
143 | 119 | 2 | 2 | 5 |
143 | 229.7 | 2 | 1 | 0 |
以上都是直接使用的情况,本身应用就会一直重复登录,但原本是单进程,现在多进程跑,难免会有被登出的情况,case执行的失败率也会提升。
解决重复登录问题
以上为考虑登录互斥的问题,我们先看下普通模式下的登录情况,在workflow/erpapi/pclogin.py
的getloginsession
下加log。
常规模式下
简单点,只跑一个文件
1 | pytest testcollection/freelanderapi/test_checkbillorder_sup.py |
7接口,近14次登录(包括saas的登录和供应商端的登录),也就是说每个接口都去登录了。
解决单进程登录问题
在conftest下添加代码
1 |
|
简单改造下test_checkbillorder_sup.py
文件
这里CheckBillOrderFlow
是一串动作。
运行test_checkbillorder_sup.py
和test_ordermanage.py
两个文件
1 | pytest testcollection/freelanderapi/test_checkbillorder_sup.py testcollection/freelanderapi/test_ordermanage.py |
只登录了一次!
现在单进程下,登录问题就解决了。
改造以支持多进程登录一次
改造前
使用两个进程
1 | pytest -n 2 testcollection/freelanderapi/test_checkbillorder_sup.py testcollection/freelanderapi/test_ordermanage.py |
使用三个进程
我们发现设置*@pytest.fixture(scope="session")*
并不能解决多进程下的登录互斥问题,每个进程都会去执行一次fixture。
经过一番搜索,找到了解决方法,使用filelock模块的FileLock功能。
改造下刚刚的once_login
方法
1 |
|
其原理是,只执行一次scope=”session”的fixture方法,其他进程从lock文件中读取。
但是显然,这么做是无效的,我们现在统一用LoginApi去调用每个模块,它是一个对象,对象如何能写入文件呢 因此这边需要写入的是token一类的值,用于接口登录。
改造思路
现有流程大致是 testcollection –> workflow –> business –> baseinterface
现在是每初始化一次workflow都去初始化了一次f6api,到business发请求这步,是带着登录后的session状态去发的请求,而现在不传递session,就需要从头到尾进行改造。
首先,fixture方法处同时登录三个端,返回cookies
在LoginApi类接收cookies,初始化freelander, maintain, stock等的时候传对应业务的cookie
在如Freelanderapi处接收cookies,初始化该业务下接口的时候(business),传cookie
改造每一个business下的方法,接收cookie, 并且sendReq中调用发送请求的时候带上cookie
改造baseinterface方法接收cookie发送请求
工程量较大,这边单独拉一个分支,并且只保留了freelander的内容进行测试。
- conftest.py下的once_login方法
1 |
|
改造后
试验pytest-xdist
改造后, 可以看到供应商账号和修理厂账号都只登录了一次, 同样执行143条case,时间来到了73.94秒,第二次执行67.81秒,比单纯使用多进程快了2分钟多,看起来账号重复登录消耗了太多时间!
case数 | 时间 | 进程数 | 失败case数 |
---|---|---|---|
143 | 73.94s | 2 | 8 |
143 | 67.71 | 2 | 8 |
试验pytest-parallel
在pytest-parallel下不知道为什么,没有执行once_login后续所有case全都失败😅,暂时先不看了。
总结
从速度上来说,无疑pytest-parallel更甚一筹,但是要确保只登录一次,暂时pytest-paraller无法搭配使用,pytest-xdist就成了首选,速度是上来了,也带来了一些错误率,多是在复杂流程的接口,执行太快了,也带来了问题,需要更合理的设置等待条件,等待时间。