How to Parametrize Tests in Python with pytest
This code demonstrates how to use pytest's @pytest.mark.parametrize decorator to run a single test function against multiple input sets, ensuring comprehensive coverage with minimal code duplication.
pip install pytest
Python code
31 linesimport pytest
def multiply(a, b):
return a * b
@pytest.mark.parametrize("x, y, expected", [
(2, 3, 6),
(4, 5, 20),
(0, 10, 0),
(7, 1, 7),
])
def test_multiply(x, y, expected):
result = multiply(x, y)
assert result == expected, f"multiply({x}, {y}) = {result}, expected {expected}"
if __name__ == "__main__":
# Demonstrate manually without pytest
cases = [
(2, 3, 6),
(4, 5, 20),
(0, 10, 0),
(7, 1, 7),
]
for x, y, expected in cases:
result = multiply(x, y)
status = "PASS" if result == expected else "FAIL"
print(f"{status}: multiply({x}, {y}) = {result} (expected {expected})")
print("All parametrized test cases completed.")
Output
PASS: multiply(2, 3) = 6 (expected 6)
PASS: multiply(4, 5) = 20 (expected 20)
PASS: multiply(0, 10) = 0 (expected 0)
PASS: multiply(7, 1) = 7 (expected 7)
All parametrized test cases completed.
How it works
The @pytest.mark.parametrize decorator in this code defines a list of argument tuples, and pytest automatically runs the test function once for each tuple, unpacking the values into the x, y, and expected parameters. This approach reduces redundancy by avoiding separate test functions for each case. pytest collects and reports each combination as an individual test, making failures easy to isolate. The assert statement with a custom message provides clear diagnostics when a case fails. The __main__ block serves as a manual demonstration, illustrating the same test logic without the pytest runner.
Common mistakes
- Forgetting to install pytest before running the test suite
- Not including an `expected` value in every parametrized tuple
- Using a list of lists instead of tuples, which can cause unpacking confusion
- Misplacing the decorator above the function definition
Variations
- Use `pytest.mark.parametrize` with separate lists for each argument and `zip` them together
- Define parametrize arguments as a list of dictionaries with `pytest.param` for more control
- Use a fixture that yields parametrized data for more complex test setups
Real-world use cases
- Database queries: run the same SQL logic test against multiple input data sets.
- API validation: test endpoint responses for various request payloads and expected status codes.
- String processing: verify a function handles different formats, edge cases, and special characters.
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.