pytest Parametrized Testing
pytest Parametrized Testing
Section titled โpytest Parametrized TestingโWhat it is
Section titled โWhat it isโ@pytest.mark.parametrize runs the same test function once per set of inputs you provide, instead of writing a near-identical test for each case. Each parameter set shows up as its own separate, individually-reportable test in the output.
Before this feature
Section titled โBefore this featureโTesting several input/output pairs for one function means either one bloated test with several asserts (if the first assert fails, you never see whether the others would have passed too), or copy-pasted near-duplicate test functions:
def test_add_positive(): assert add(2, 3) == 5
def test_add_negative(): assert add(-1, -1) == -2
def test_add_zero(): assert add(0, 0) == 0# repetitive, and adding a new case means adding a whole new functionAfter this feature
Section titled โAfter this featureโimport pytest
def add(a, b): return a + b
@pytest.mark.parametrize("a, b, expected", [ (2, 3, 5), (-1, -1, -2), (0, 0, 0), (100, -100, 0),])def test_add(a, b, expected): assert add(a, b) == expected
# pytest runs this as 4 separate tests:# test_add[2-3-5], test_add[-1--1--2], test_add[0-0-0], test_add[100--100-0]Why this is better
Section titled โWhy this is betterโ- One test body, many cases: adding a new case is a new tuple in the list, not a new function.
- Each case reports independently: if
test_add[100--100-0]fails, pytest tells you exactly which parameter set failed โ the others still ran and reported their own pass/fail. - Scales cleanly: covering edge cases (zero, negative, boundary values, malformed input) is just more rows in the parameter list, keeping the test suiteโs actual assertion logic in one place.
Key notes / edge cases
Section titled โKey notes / edge casesโ- The string
"a, b, expected"names the parameters in the same order as each tuple โ a mismatch between the names and tuple order is a common copy-paste mistake. pytest.param(..., id="descriptive-name")lets you give a readable test ID instead of pytestโs auto-generated one, which helps when parameter values are long or non-obvious in test output.- You can stack multiple
@pytest.mark.parametrizedecorators on one test to get the cross-product of both parameter sets โ useful, but grows combinations fast, so use deliberately.
@pytest.mark.parametrize("a, b, expected", [ pytest.param(2, 3, 5, id="basic-positive"), pytest.param(-1, -1, -2, id="both-negative"),])def test_add(a, b, expected): assert add(a, b) == expectedQuick practice
Section titled โQuick practiceโ-
If
@pytest.mark.parametrizeis given 4 tuples of inputs, how many separate test runs does pytest report?Answer
4 โ one per parameter tuple, each reported and can pass/fail independently. -
Whatโs the advantage of parametrized tests over one test function with 4 separate
assertstatements?Answer
Each case is isolated โ if one fails, the others still run and report their own result, instead of the first failing `assert` stopping the whole test before the rest are checked. -
How do you give a parametrized test case a custom, readable ID instead of pytestโs auto-generated one?
Answer
Use `pytest.param(..., id="my-readable-name")` instead of a plain tuple.