pytest-xdist

pytest-xdist 是一个 pytest 插件, 可以将测试用例分布在多个 CPU 上以加快执行速度。

并发执行

通过sleep的模拟耗时的测试用例:

# test_xdist_sleep.yaml

name: 模拟耗时1秒用例
mark:
  - parametrize:
      - n
      - [1,2,3,4]
steps:
  - sleep: 1

每个用例耗时1秒,则4个用例耗时4秒:

(.venv) C:\demo\pytest-yaml-demo>pytest -v
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.2.2, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: xdist-3.6.1, yaml-1.1.1
collected 4 items

tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[1] PASSED              [ 25%]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[2] PASSED              [ 50%]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[3] PASSED              [ 75%]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[4] PASSED              [100%]

============================== 4 passed in 4.04s ===============================

使用xdist插件进行并发执行的结果:

(.venv) C:\demo\pytest-yaml-demo>pytest -v -n 4
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.2.2, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: xdist-3.6.1, yaml-1.1.1
4 workers [4 items]
scheduling tests via LoadScheduling

tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[1]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[4]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[3]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[2]
[gw3] [ 25%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[4]
[gw0] [ 50%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[1]
[gw2] [ 75%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[3]
[gw1] [100%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[2]

============================== 4 passed in 2.86s ===============================

按文件分组

使用参数 --dist loadfile--dist loadscope 可确保同一个yaml文件中的所有用例在同一个worker中运行。 如果用例请求了昂贵的模块级或类级fixture,这将非常有用。

(.venv) C:\demo\pytest-yaml-demo>pytest -v -n 4 --dist loadscope
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.2.2, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: xdist-3.6.1, yaml-1.1.1
4 workers [4 items]
scheduling tests via LoadScopeScheduling

tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[1]
[gw0] [ 25%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[1]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[2]
[gw0] [ 50%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[2]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[3]
[gw0] [ 75%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[3]
tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[4]
[gw0] [100%] PASSED tests/plugins/test_xdist_sleep.yaml::模拟耗时1秒用例[4]

============================== 4 passed in 5.81s ===============================

从结果来看,虽然启动了4个worker,但是所有的用例由同一个 worker (gw0) 执行。

自定义分组

使用参数 --dist loadgroup 用例将按照标记 xdist_group 进行自定义分组。 同一分组的用例,可以确保被同一个worker执行。

# test_xdist_group.yaml

name: a
mark:
  - xdist_group: group1
steps:
  - sleep: 1

---
name: b
mark:
  - xdist_group: group1
steps:
  - sleep: 1

---
name: c
mark:
  - xdist_group: group1
steps:
  - sleep: 1

---
name: d
mark:
  - xdist_group: group2
steps:
  - sleep: 1

执行结果:

(.venv) C:\demo\pytest-yaml-demo>pytest -v -n 4 --dist loadgroup
============================= test session starts ==============================
platform win32 -- Python 3.12.0, pytest-8.2.2, pluggy-1.5.0
cachedir: .pytest_cache
rootdir: C:\demo\pytest-yaml-demo
configfile: pytest.ini
plugins: xdist-3.6.1, yaml-1.1.1
4 workers [4 items]
scheduling tests via LoadGroupScheduling

tests/plugins/test_xdist_group.yaml::d@group2
tests/plugins/test_xdist_group.yaml::a@group1
[gw0] [ 25%] PASSED tests/plugins/test_xdist_group.yaml::a@group1
[gw1] [ 50%] PASSED tests/plugins/test_xdist_group.yaml::d@group2
tests/plugins/test_xdist_group.yaml::b@group1
[gw0] [ 75%] PASSED tests/plugins/test_xdist_group.yaml::b@group1
tests/plugins/test_xdist_group.yaml::c@group1
[gw0] [100%] PASSED tests/plugins/test_xdist_group.yaml::c@group1

============================== 4 passed in 4.89s ===============================

从结果来看, group1的3个用例在同一个 worker (gw0) 执行, group2的1个用例由另一个 worker (gw1)执行。