Python tutorials > Testing > pytest > What is pytest parametrization?
What is pytest parametrization?
pytest
parametrization is a powerful feature that allows you to run the same test function multiple times with different sets of input data. This significantly reduces code duplication and makes your tests more comprehensive by covering a wider range of scenarios. It's a cornerstone for effective testing, especially when dealing with functions that need to be verified against various inputs and expected outputs.
Basic Parametrization Example
This example demonstrates the fundamental usage of pytest.mark.parametrize
. The @pytest.mark.parametrize
decorator takes two arguments: a comma-separated string representing the names of the parameters to be passed to the test function, and a list of tuples, where each tuple represents a set of values for those parameters.
In this case, the test function test_square
will be executed three times. The first time, input_value
will be 2 and expected_result
will be 4. The second time, input_value
will be 3 and expected_result
will be 9, and so on.
import pytest
@pytest.mark.parametrize("input_value, expected_result", [
(2, 4),
(3, 9),
(4, 16),
])
def test_square(input_value, expected_result):
assert input_value * input_value == expected_result
Concepts Behind the Snippet
The core concept is to avoid writing redundant test functions for different inputs. Without parametrization, you'd need to create separate test functions like test_square_2()
, test_square_3()
, etc., which is highly inefficient. Parametrization allows you to define the input values and expected results in a structured way, making your tests more readable and maintainable. Pytest handles the execution of the test function for each set of parameters.
Real-Life Use Case Section
Consider testing a function that validates email addresses. You'd want to test it with a variety of valid and invalid email formats. Parametrization is ideal for this:
Imagine you have a function is_valid_email(email)
. You can use parametrization to test it with different email addresses:
python
import pytest
@pytest.mark.parametrize("email, expected", [
("test@example.com", True),
("invalid-email", False),
("test.with.dots@example.co.uk", True),
("", False),
])
def test_is_valid_email(email, expected):
assert is_valid_email(email) == expected
This neatly tests the function against a variety of cases without code duplication.
Best Practices
ids
for better test reporting: The ids
argument to pytest.mark.parametrize
allows you to provide custom names for each test case, making it easier to identify failing tests.
Interview Tip
When discussing pytest parametrization in an interview, emphasize its role in reducing code duplication and improving test coverage. Mention the use of @pytest.mark.parametrize
and explain how to define the parameters and their corresponding values. Also, highlight the benefits of using ids
for clearer test reporting.
When to Use Them
Use parametrization whenever you need to test a function with multiple sets of input data and expected outputs. It's particularly useful for testing functions that handle edge cases, boundary conditions, or different types of inputs. If you find yourself writing the same test logic repeatedly with only slight variations in input, parametrization is likely the right approach.
Memory Footprint
Parametrization generally doesn't introduce a significant memory overhead. Pytest executes the test function for each set of parameters, so the memory usage is roughly equivalent to running the test function independently for each case. For extremely large datasets, consider using generators to provide the parameter values incrementally, which can reduce memory consumption.
Alternatives
While pytest.mark.parametrize
is the standard way to achieve parametrization in pytest, other approaches exist. For instance:
Pros
Cons
Using `ids` for descriptive test names
The `ids` parameter allows you to name each test case. Instead of pytest generating names like `test_square[0-4]`, the test report will show `test_square[square_of_2]`, `test_square[square_of_3]`, etc. This makes it much easier to identify which specific test case failed.
import pytest
@pytest.mark.parametrize(
"input_value, expected_result",
[
(2, 4),
(3, 9),
(4, 16),
],
ids=["square_of_2", "square_of_3", "square_of_4"],
)
def test_square(input_value, expected_result):
assert input_value * input_value == expected_result
FAQ
-
How do I access the parameter values within the test function?
The parameter values are passed as arguments to the test function. In the example above,input_value
andexpected_result
are the parameters, and their corresponding values are passed to thetest_square
function during each execution. -
Can I parametrize multiple test functions?
Yes, you can apply the@pytest.mark.parametrize
decorator to multiple test functions. Each function will be executed with the specified parameter sets. -
What happens if one of the parametrized tests fails?
Pytest will continue to execute the remaining parametrized tests even if one of them fails. The test report will indicate which tests passed and which failed. -
Can I use parametrization with fixtures?
Yes, you can combine parametrization with fixtures. Fixtures can provide setup and teardown logic for each parametrized test case, enabling more complex testing scenarios. Userequest.param
within the fixture to access the parameter value.