diff --git a/CHANGELOG.md b/CHANGELOG.md index e952df9..99688a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Use mean test duration for tests without stored duration instead of average ## [0.10.0] - 2024-10-16 ### Added @@ -63,4 +64,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), [0.6.0]: https://github.com/jerry-git/pytest-split/compare/0.5.0...0.6.0 [0.5.0]: https://github.com/jerry-git/pytest-split/compare/0.4.0...0.5.0 [0.4.0]: https://github.com/jerry-git/pytest-split/tree/0.4.0 - diff --git a/README.md b/README.md index 11f8a00..7dd650c 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ pytest --splits 3 --group 3 ``` Time goes by, new tests are added and old ones are removed/renamed during development. No worries! -`pytest-split` assumes average test execution time (calculated based on the stored information) for every test which does not have duration information stored. +`pytest-split` assumes mean 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-durations` to ensure that the splitting is in balance. diff --git a/src/pytest_split/algorithms.py b/src/pytest_split/algorithms.py index 8c47bd4..94586d7 100644 --- a/src/pytest_split/algorithms.py +++ b/src/pytest_split/algorithms.py @@ -2,6 +2,7 @@ import heapq from abc import ABC, abstractmethod from operator import itemgetter +from statistics import mean from typing import TYPE_CHECKING, NamedTuple if TYPE_CHECKING: @@ -154,20 +155,20 @@ def _get_items_with_durations( items: "List[nodes.Item]", durations: "Dict[str, float]" ) -> "List[Tuple[nodes.Item, float]]": durations = _remove_irrelevant_durations(items, durations) - avg_duration_per_test = _get_avg_duration_per_test(durations) + mean_duration_per_test = _get_mean_duration_per_test(durations) items_with_durations = [ - (item, durations.get(item.nodeid, avg_duration_per_test)) for item in items + (item, durations.get(item.nodeid, mean_duration_per_test)) for item in items ] return items_with_durations -def _get_avg_duration_per_test(durations: "Dict[str, float]") -> float: +def _get_mean_duration_per_test(durations: "Dict[str, float]") -> float: if durations: - avg_duration_per_test = sum(durations.values()) / len(durations) + mean_duration_per_test = mean(durations.values()) else: # If there are no durations, give every test the same arbitrary value - avg_duration_per_test = 1 - return avg_duration_per_test + mean_duration_per_test = 1 + return mean_duration_per_test def _remove_irrelevant_durations(