Mock Python version with unittest.mock.patch
Use unittest.mock.patch to simulate a specific Python version and test version-dependent behavior.
Python code
16 linesimport sys
import unittest
from unittest.mock import patch
class TestPythonVersion(unittest.TestCase):
@patch("sys.version_info", (3, 9, 0, "final", 0))
def test_python_version_pinned(self):
self.assertEqual(sys.version_info[:2], (3, 9))
print(f"Pinned version: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
def test_real_python_version(self):
print(f"Actual version: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
self.assertTrue(sys.version_info >= (3, 9))
if __name__ == "__main__":
unittest.main()
Output
Pinned version: 3.9.0
.
Actual version: 3.10.12 (example)
.
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
How it works
The @patch("sys.version_info", (3, 9, 0, "final", 0)) decorator temporarily replaces sys.version_info with a fake tuple, letting you test code that branches on Python version. Since patch applies only to the decorated test method, other tests still see the real interpreter version. This is great for testing compatibility layers, conditional imports, or deprecated API warnings. To simulate different versions, just pass a different tuple—like (3, 11, 4, "final", 0).
Common mistakes
- Patching the wrong path—must match where the object is used, not where it's defined.
- Forgetting that `patch` as a decorator only affects the decorated test method.
- Assuming `sys.version_info` is a simple tuple when it's actually a `sys.version_info` object; a tuple works fine for equality but may break attribute access beyond the first two elements.
Variations
- Use `with patch("sys.version_info", (3, 8, 0, "final", 0)):` statement for conditional patching.
- Use `unittest.mock.mock_version` to simulate version in third-party libraries.
Real-world use cases
- Testing compatibility of your library against multiple Python versions in CI without separate jobs.
- Verifying that code paths handling deprecated features behave correctly on older interpreters.
- Ensuring feature flags or version-dependent imports activate the right module during testing.
Sponsored
More from Modern tooling
- Build a Recipe Runner Mock in Python easy
- Build a Textual TUI App Skeleton in Python easy
- Configure ruff linter rules in pyproject.toml with Python easy
- Data Conversion Helper Functions in Python easy
- How to Bind and Mock structlog Context in Python medium
- How to Build a Chainable Filter Helper in Python easy
Keep learning
Related tutorials and quizzes for this topic.