From 96b786b63b6e69ed6c5c24fd47c839eac7b7ad43 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Wed, 21 Feb 2024 16:16:34 +0100 Subject: [PATCH] chore: MockTiming - move impl to _pytest.timing --- src/_pytest/timing.py | 36 ++++++++++++++++++++++++++++++++++++ testing/conftest.py | 21 ++------------------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/_pytest/timing.py b/src/_pytest/timing.py index b23c7f69e..e2dde1617 100644 --- a/src/_pytest/timing.py +++ b/src/_pytest/timing.py @@ -8,9 +8,45 @@ Fixture "mock_timing" also interacts with this module for pytest's own tests. from __future__ import annotations +import dataclasses +from datetime import datetime from time import perf_counter from time import sleep from time import time +from typing import TYPE_CHECKING + + +if TYPE_CHECKING: + from pytest import MonkeyPatch + + +@dataclasses.dataclass +class MockTiming: + """Mocks _pytest.timing with a known object that can be used to control timing in tests + deterministically. + + pytest itself should always use functions from `_pytest.timing` instead of `time` directly. + + This then allows us more control over time during testing, if testing code also + uses `_pytest.timing` functions. + + Time is static, and only advances through `sleep` calls, thus tests might sleep over large + numbers and obtain accurate time() calls at the end, making tests reliable and instant.""" + + _current_time: float = datetime(2020, 5, 22, 14, 20, 50).timestamp() # noqa: RUF009 + + def sleep(self, seconds: float) -> None: + self._current_time += seconds + + def time(self) -> float: + return self._current_time + + def patch(self, monkeypatch: MonkeyPatch) -> None: + from _pytest import timing # noqa: PLW0406 + + monkeypatch.setattr(timing, "sleep", self.sleep) + monkeypatch.setattr(timing, "time", self.time) + monkeypatch.setattr(timing, "perf_counter", self.time) __all__ = ["perf_counter", "sleep", "time"] diff --git a/testing/conftest.py b/testing/conftest.py index 24e5d1830..3a5421f45 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,7 +1,6 @@ # mypy: allow-untyped-defs from __future__ import annotations -import dataclasses import re import sys from typing import Generator @@ -226,24 +225,8 @@ def mock_timing(monkeypatch: MonkeyPatch): Time is static, and only advances through `sleep` calls, thus tests might sleep over large numbers and obtain accurate time() calls at the end, making tests reliable and instant. """ - - @dataclasses.dataclass - class MockTiming: - _current_time: float = 1590150050.0 - - def sleep(self, seconds: float) -> None: - self._current_time += seconds - - def time(self) -> float: - return self._current_time - - def patch(self) -> None: - from _pytest import timing - - monkeypatch.setattr(timing, "sleep", self.sleep) - monkeypatch.setattr(timing, "time", self.time) - monkeypatch.setattr(timing, "perf_counter", self.time) + from _pytest.timing import MockTiming result = MockTiming() - result.patch() + result.patch(monkeypatch) return result