pytest-xdist: group tests in a module to a subprocess

First, If you would like to know how pytest-xdist works under the covers, checkout OVERVIEW.

with pytest-xdist, you have 2 options to run tests in parallel:

  • Running tests using multiple CPUs
    • pytest -n 4 -m api_regression
  • Running tests in a Python subprocess
    • pytest -d --tx 4*popen//python=python3.7 -m api_regression

There might be a situation that you want to run all tests in one module sequentially. In order to do that but also keep tests running in parallel, you can change test distribution algorithm to fulfill that purpose.

By default, using these options will send pending tests to any worker that is available, without any guaranteed order. You can change the test distribution algorithm this with the –dist option. It takes these values:

  • –dist no: The default algorithm, distributing one test at a time.
  • –dist loadscope: Tests are grouped by module for test functions and by class for test methods. Groups are distributed to available workers as whole units. This guarantees that all tests in a group run in the same process. This can be useful if you have expensive module-level or class-level fixtures. Grouping by class takes priority over grouping by module.
  • –dist loadfile: Tests are grouped by their containing file. Groups are distributed to available workers as whole units. This guarantees that all tests in a file run in the same worker.

To group tests in a module to run in one subprocess or CPU session, let specify –dist=loadscope

pytest --dist=loadscope --tx 2*popen//python=python3.7 -m api_regression

Below console log is shown when run with default test distribution algorithm (–dist=no).

You can see tests in single module test_get_user_info.py are run in both subprocess 0 and subprocee 1

gw0 [10] / gw1 [10]
scheduling tests via LoadScheduling

[gw1] [ 10%] PASSED tests/api/test_get_user_info.py::test_get_001
[gw0] [ 20%] PASSED tests/api/ test_get_user_info .py::test_get_002
[gw0] [ 30%] PASSED tests/api/ test_get_user_info .py::test_get_003
[gw1] [ 40%] PASSED tests/api/test_update_user_info.py::test_update_001
[gw1] [ 50%] PASSED tests/api/ test_update_user_info .py::test_update_002
[gw0] [ 60%] PASSED tests/api/ test_update_user_info .py::test_update_003
[gw1] [ 70%] PASSED tests/api/ test_update_user_info .py::test_update_004
[gw1] [ 80%] PASSED tests/api/ test_update_user_info .py::test_update_005
[gw0] [ 90%] PASSED tests/api/ test_update_user_info .py::test_update_006
[gw1] [100%] PASSED tests/api/ test_update_user_info .py::test_update_007

============== 10 passed in 62.74s (0:01:02) ==============

Below console log is shown when run with test distribution algorithm –dist=loadscope

You can see tests in single module test_get_user_info.py are run in only subprocess 0

gw0 [10] / gw1 [10]
scheduling tests via LoadScopeScheduling

[gw1] [ 10%] PASSED tests/api/ test_update_user_info .py::test_update_001
[gw0] [ 20%] PASSED tests/api/ test_get_user_info .py::test_get_001
[gw1] [ 30%] PASSED tests/api/ test_update_user_info .py::test_update_002
[gw0] [ 40%] PASSED tests/api/ test_get_user_info .py::test_get_002
[gw1] [ 50%] PASSED tests/api/ test_update_user_info .py::test_update_003
[gw0] [ 60%] PASSED tests/api/ test_get_user_info .py::test_get_003
[gw1] [ 70%] PASSED tests/api/ test_update_user_info .py::test_update_004
[gw1] [ 80%] PASSED tests/api/ test_update_user_info .py::test_update_005
[gw1] [ 90%] PASSED tests/api/ test_update_user_info .py::test_update_006
[gw1] [100%] PASSED tests/api/ test_update_user_info .py::test_update_007

============== 10 passed in 62.74s (0:01:02) ==============


Reference Links:

https://pypi.org/project/pytest-xdist/

https://github.com/pytest-dev/pytest-xdist/blob/master/OVERVIEW.md

Leave a comment