如何分布式执行接口自动化测试用例(下)

       继《如何分布式执行接口自动化测试用例(上)》文章,我们了解了pytest-xdist插件能实现接口自动化用例的分布式运行,但仍还存在不少疑问,比如:pytest-xdist的原理流程是怎样的?分布式能否将同一模块的用例在一个node上执行避免混乱?如何控制session级别的夹具的执行次数等等,今天我们就一一讲下这些:

一、原理和流程

xdist 的分布式类似于一主多从的结构,master 机负责下发命令,控制 slave 机;slave 机根据 master 机的命令执行特定测试任务。在 xdist 中,主是 master,从是 workers。

分布式测试的原理:

(1)xdist 会产生一个或多个 workers,workers 都通过 master 来控制;

(2)每个 worker 负责执行完整的测试用例集,然后按照 master 的要求运行测试,而 master 机不执行测试任务。

分布式测试的流程:

1、创建 worker

(1)master 会在总测试会话(test session)开始前产生一个或多个 worker;

(2)master 和 worker 之间是通过 execnet 和网关来通信的;

(3)实际编译执行测试代码的 worker 可能是本地机器也可能是远程机器。

2、收集测试用例

(1)每个 worker 类似一个迷你型的 pytest 执行器;

(2)worker 会执行一个完整的 test collection 过程(收集所有测试用例的过程);

(3)然后把测试用例的 ids 返回给 master;

(4)master 是不会执行任何测试用例集的。

3、master 检测 workers 收集到的测试用例集

(1)master 接收到所有 worker 收集的测试用例集之后,master 会进行一些完整性检查,以确保所有 worker 都收集到一样的测试用例集(包括顺序);

(2)如果检查通过,会将测试用例的 ids 列表转换成简单的索引列表,每个索引对应一个测试用例的在原来测试集中的位置;

(3)所有的节点都保存着相同的测试用例集,并且使用这种方式可以节省带宽,因为 master 只需要告知 workers 需要执行的测试用例对应的索引,而不用告知完整的测试用例信息。

4、测试用例分发

--dist-mode 选项

each:master 将完整的测试索引列表分发到每个 worker。

load:master 将大约25%的测试用例以轮询的方式分发到各个 worker,剩余的测试用例则会等待 workers 执行完测试用例以后再分发。

注:可以使用 pytest_xdist_make_scheduler 这个 hook 来实现自定义测试分发逻辑。

5、测试用例的执行

(1)workers 重写了 pytest_runtestloop(pytest 的默认实现是循环执行所有在 test session 这个对象里面收集到的测试用例);

(2)但是在 xdist 里, workers 实际上是等待 master 为其发送需要执行的测试用例;

(3)当 worker 收到测试任务, 就顺序执行 pytest_runtest_protocol;

(4)值得注意的一个细节是:workers 必须始终保持至少一个测试用例在任务队列里, 以兼容 pytest_runtest_protocol(item, nextitem)hook 的参数要求,为了将 nextitem 传给 hook;

(5)worker 会在执行最后一个测试项前等待 master 的更多指令;

(6)如果它收到了更多测试项, 那么就可以安全的执行 pytest_runtest_protocol,因为这时 nextitem 参数已经可以确定;

(7)如果它收到一个 "shutdown" 信号, 那么就将 nextitem 参数设为 None, 然后执行 pytest_runtest_protocol。

6、测试用例再分发

--dist-mode=load

(1)当 workers 开始/结束执行时,会把测试结果返回给 master,这样其他 pytest hook 比如(pytest_runtest_protocol 和 pytest_runtest_protocol 就可以正常执行);

(2)master 在 worker 执行完一个测试后,基于测试执行时长以及每个 work 剩余测试用例综合决定是否向这个 worker 发送更多的测试用例。

7、测试结束

(1)当 master 没有更多执行测试任务时,它会发送一个 "shutdown" 信号给所有 worker;

(2)当 worker 将剩余测试用例执行完后退出进程;

(3)master 等待所有 worker 全部退出;

(4)此时仍需要处理诸如 pytest_runtest_logreport 等事件。

二、按照一定顺序执行

pytest-xdist 默认是无序执行的,可以通过 --dist 参数来控制执行顺序。

--dist=loadscope:将按照同一个模块 module 下的函数和同一个测试类 class 下的方法来分组,然后将每个测试组发给可以执行的 worker,确保同一个组的测试用例在同一个进程中执行。目前无法自定义分组,按类 class 分组优先于按模块 module 分组。

--dist=loadfile:按照同一个文件名来分组,然后将每个测试组发给可以执行的 worker,确保同一个组的测试用例在同一个进程中执行。

在UCS接口测试套中,我们是以模块来区分的,如:ACS、Account、Group、Org等模块。因此,可执行命令如下:

pytest -s -v -n auto --dist=loadscope

执行结果如下图:    

       从图中可以看出执行PC虽然是8核,但因为我们只有test_xdist.py、test_xdist01.py、test_xdist02.py三个模块,故只用到了3核。test_xdist.py的测试实例只在gw0上执行,test_xdist01.py的测试实例只在gw1上执行,test_xdist02.py的测试实例只在gw2上执行。

三、使 scope=session 的 fixture 在 test session 中仅执行一次

pytest-xdist 是让每个 worker 进程执行属于自己的测试用例集下的所有测试用例。

这意味着在不同进程中,不同的测试用例可能会调用同一个 scope 范围级别较高(例如session)的 fixture,该 fixture 则会被执行多次,这不符合 scope=session 的预期。

尽管 pytest-xdist 没有内置的支持来确保会话范围的 fixture 仅执行一次,但是可以通过使用锁定文件进行进程间通信来实现。如下示例:

#!/usr/bin/env python
# --encoding=utf-8
​
import time
import pytest
from filelock import FileLock
​
​
@pytest.fixture(scope="session")
def login(tmp_path_factory,worker_id):
    print(f"===登陆====")
    print(f"worker_id:{worker_id}")
    print(f"tmp_path_factory:{tmp_path_factory}")
    root_tmp_dir = tmp_path_factory.getbasetemp().parent
    print(f"root_tmp_dir:{root_tmp_dir}")
    fn = root_tmp_dir / "data.json"
    print(f"fn:{fn}")
    # 如果是单机运行,则运行这里的代码块【不可删除、修改】
    if worker_id == "master":
        print("11111")
    else:
        with FileLock(str(fn) + ".lock"):
            if fn.is_file():
                print(time.time())
                print(f"第N次访问")
            else:
                print("首次访问")
                fn.write_text("test")

执行

pytest -v -n auto --dist=loadscope --alluredir E:\xdistTest\log\allure-results

运行报告如下:    

 

从报告可以看出只有test_xdist.py::test_tmall_001执行了“首次访问”,从而间接达到了session的效果。    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值