Package: pytest-split
pytest-splitDocumentation:https://jerry-git.github.io/pytest-splitSource Code:https://github.com/jerry-git/pytest-splitPyPI:https://pypi.org/project/pytest-split/Pytest plugin which splits the test suite to equally sized "sub suites" based on test execution time.MotivationSplitting the test suite is a prerequisite for parallelization (who does not want faster CI builds?). It's valuable to have sub suites which execution time is around the same.pytest-test-groupsis great but it does not take into account the execution time of sub suites which can lead to notably unbalanced execution times between the sub suites.pytest-xdistis great but it's not suitable for all use cases.
For example, some test suites may be fragile considering the order in which the tests are executed.
This is of course a fundamental problem in the suite itself but sometimes it's not worth the effort to refactor, especially if the suite is huge (and smells a bit like legacy).
Additionally,pytest-splitmay be a better fit in some use cases considering distributed execution.Installationpipinstallpytest-splitUsageFirst we have to store test durations from a complete test suite run.
This produces .test_durations file which should be stored in the repo in order to have it available during future test runs.
The file path is configurable via--durations-pathCLI option.pytest--store-durationsThen we can have as many splits as we want:pytest--splits3--group1pytest--splits3--group2pytest--splits3--group3Time goes by, new tests are added and old ones are removed/renamed during development. No worries!pytest-splitassumes average test execution time (calculated based on the stored information) for every test which does not have duration information stored.
Thus, there's no need to store durations after changing the test suite.
However, when there are major changes in the suite compared to what's stored in .test_durations, it's recommended to update the duration information with--store-durationsto ensure that the splitting is in balance.The splitting algorithm can be controlled with the--splitting-algorithmCLI option and defaults toduration_based_chunks. For more information about the different algorithms and their tradeoffs, please see the section below.CLI commandsslowest-testsLists the slowest tests based on the information stored in the test durations file. Seeslowest-tests --helpfor more
information.Interactions with other pytest pluginspytest-random-orderandpytest-randomly:
⚠️pytest-splitrunning with theduration_based_chunksalgorithm isincompatiblewith test-order-randomization plugins.
Test selection in the groups happens after randomization, potentially causing some tests to be selected in several groups and others not at all.
Instead, a global random seed needs to be computed before running the tests (for example using$RANDOMfrom the shell) and that single seed then needs to be used for all groups by setting the--random-order-seedoption.nbval:pytest-splitcould, in principle, break up a single IPython Notebook into different test groups. This most likely causes broken up pieces to fail (for the very least, packageimports are usually done at Cell 1, and so, any broken up piece that doesn't contain Cell 1 will certainly fail). To avoid this, after splitting step is done, test groups are reorganized based on a simple algorithm illustrated in the following cartoon:where the letters (A to E) refer to individual IPython Notebooks, and the numbers refer to the corresponding cell number.Splitting algorithmsThe plugin supports multiple algorithms to split tests into groups.
Each algorithm makes different tradeoffs, but generallyleast_durationshould give more balanced groups.AlgorithmMaintains Absolute OrderMaintains Relative OrderSplit QualityWorks with random orderingduration_based_chunks✅✅Good❌least_duration❌✅Better✅Explanation of the terms in the table:Absolute Order: whether each group contains all tests between first and last element in the same order as the original list of testsRelative Order: whether each test in each group has the same relative order to its neighbours in the group as in the original list of testsWorks with random ordering: whether the algorithm works with test-shuffling tools such aspytest-randomlyTheduration_based_chunksalgorithm aims to find optimal boundaries for the list of tests and every test group contains all tests between the start and end boundary.
Theleast_durationalgorithm walks the list of tests and assigns each test to the group with the smallest current duration.Demo with GitHub ActionsDevelopmentClone this repositoryRequirements:PoetryPython 3.7+Create a virtual environment and install the dependenciespoetryinstallActivate the virtual environmentpoetryshellTestingpytestDocumentationThe documentation is automatically generated from the content of thedocs directoryand from the docstrings
of the public signatures of the source code. The documentation is updated and published as aGithub project pageautomatically as part each release.ReleasingTrigger theDraft release workflow(pressRun workflow). This will update the changelog & version and create a GitHub release which is inDraftstate.Find the draft release from theGitHub releasesand publish it. When
a release is published, it'll triggerreleaseworkflow which creates PyPI
release and deploys updated documentation.Pre-commitPre-commit hooks run all the auto-formatters (e.g.black), linters (e.g.mypy,ruff), and other quality
checks to make sure the changeset is in good shape before a commit/push happens.You can install the hooks with (runs for each commit):pre-commitinstallOr if you want them to run only for each push:pre-commitinstall-tpre-pushOr if you want e.g. want to run all checks manually for all files:pre-commitrun--all-filesThis project was generated using thewolt-python-package-cookiecuttertemplate.