python-3.x - 并行 Pytest 夹具处理
问题描述
我正在使用 PyTest,假设我有一个名为 的测试函数test_func
,它有两个名为docker_mysql
和的参数docker_clickhouse
,它们是 PyTest 术语中的函数夹具。在这两个函数中,我正在拉取 docker 映像并启动它。由于fixtures的机制,test_func
一步步调用fixtures,所以,第二个docker容器只有在第一个启动后才会运行。
所以,问题是:如何并行化拉取 docker 容器的过程以节省时间,因为在不久的将来等待许多 docker 容器在队列中会很烦人。
就个人而言,我尝试过pytest-xdist但在 CI-CD 中我没有提到速度的任何变化。另外,我尝试制作可以使用 执行线程的夹具from threading import Thread
,但我崩溃了。
解决方案
我使用 Thread 进行了尝试,并且成功了。
from datetime import datetime
from queue import Queue
from threading import Thread
import time
import pytest
def _pull_and_start_docker_mysql():
print(datetime.now(), "Start downloading docker_mysql")
time.sleep(5) # Simulate download
print(datetime.now(), "Finished downloading docker_mysql")
return "MySQL"
def _pull_and_start_docker_clickhouse():
print(datetime.now(), "Start downloading docker_clickhouse")
time.sleep(8) # Simulate download
print(datetime.now(), "Finished downloading docker_clickhouse")
return "Clickhouse"
@pytest.fixture(scope="session")
def docker():
results = Queue() # Needed to store the results of the threads
p1 = Thread(target=lambda: results.put(("docker_mysql", _pull_and_start_docker_mysql()))) # To identify the result, we put an identifier name "docker_mysql"
p2 = Thread(target=lambda: results.put(("docker_clickhouse", _pull_and_start_docker_clickhouse()))) # To identify the result, we put an identifier name "docker_clickhouse"
p1.start()
p2.start()
p1.join()
p2.join()
return [results.get() for _ in range(results.qsize())]
def test_func(docker):
print("Inside test_func", docker)
assert True
def test_func2(docker):
print("Inside test_func2", docker)
assert True
$ pytest -rP
=========================================================================================== test session starts ===========================================================================================
collected 2 items
test_docker.py .. [100%]
================================================================================================= PASSES ==================================================================================================
________________________________________________________________________________________________ test_func ________________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout setup ------------------------------------------------------------------------------------------
2021-08-17 01:26:21.113417 Start downloading docker_mysql
2021-08-17 01:26:21.113675 Start downloading docker_clickhouse
2021-08-17 01:26:26.125081 Finished downloading docker_mysql
2021-08-17 01:26:29.122935 Finished downloading docker_clickhouse
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
Inside test_func [('docker_mysql', 'MySQL'), ('docker_clickhouse', 'Clickhouse')]
_______________________________________________________________________________________________ test_func2 ________________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
Inside test_func2 [('docker_mysql', 'MySQL'), ('docker_clickhouse', 'Clickhouse')]
============================================================================================ 2 passed in 8.04s ============================================================================================
一些注意事项:
- 从日志中可以看出,进程在 01:26:21
docker_mysql
同时docker_clickhouse
开始,分别在 5 秒和 8 秒的睡眠后结束(模拟不同的执行时间)。 - 我使用了此处
"session"
记录的范围,因此它不会为每个测试重新执行夹具,正如在运行和后在日志中可见的那样。检查这是否也适用于您的场景。test_func
test_func2
- 目前,夹具响应的格式是 <Identifier, Result> 的列表,例如
[('docker_mysql', 'MySQL'), ...]
。您可能需要重新格式化它,例如根据您的用例进行 dict。
推荐阅读
- php - 从作为对象元素的数组中删除元素
- docker - 使用 docker-compose 进行 Vue.js 本地开发
- c# - 在 C# 中与 Google Admin SDK 集成
- javascript - ExpressJS 是否遵循 MVC 模式?
- nosql - 如何在 ArangoDB 中存储位置?
- node.js - 输入验证失败时如何防止 Multer 文件上传
- javadoc - Javadoc:“继承自的方法”和“声明的方法”之间的区别
- jquery - 使用 Jquery 将 div 的内容移动到具有匹配数据属性值的另一个 div
- express - 迁移后 Heroku 无法识别列
- angular - 在 Angular 中显示 firebase CRUD 请求的加载栏