Skip to content

pytest Parametrized Testing

@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.

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 function
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]
  • 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.
  • 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.parametrize decorators 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) == expected
  1. If @pytest.mark.parametrize is given 4 tuples of inputs, how many separate test runs does pytest report?

    Answer4 โ€” one per parameter tuple, each reported and can pass/fail independently.
  2. Whatโ€™s the advantage of parametrized tests over one test function with 4 separate assert statements?

    AnswerEach 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.
  3. How do you give a parametrized test case a custom, readable ID instead of pytestโ€™s auto-generated one?

    AnswerUse `pytest.param(..., id="my-readable-name")` instead of a plain tuple.