@pytest.mark.parametrize
Overview
**Parametrize** is a decorator that runs the exact same test multiple times with different inputs. It takes a string of argument names, and a list of values. Here is a worked example testing if numbers are even: ```python import pytest def is_even(n): return n % 2 == 0 @pytest.mark.parametrize('num, expected', [ (2, True), (4, True), (5, False) ]) def test_is_even(num, expected): assert is_even(num) == expected ``` pytest runs `test_is_even` three times. The first time, `num` is 2 and `expected` is True. The third time, `num` is 5 and `expected` is False. Now, look at this faded example where one step is blank: ```python import pytest @pytest.mark._______('word', ['apple', 'banana']) def test_words(word): assert len(word) > 0 ``` To run this test twice (once for 'apple', once for 'banana'), we fill in the blank with `parametrize`.
Without parametrize, you have to write many identical test functions or use a for-loop inside a single test (which stops testing on the first failure). Parametrize treats each input as an independent test.
Where used: pytest test suites
Why learn this
- Testing many edge cases without writing boilerplate code.
- Keeping test files short and readable.
Code walkthrough
import pytest
@pytest.mark.parametrize('x', [10, 20])
def test_values(x):
print(f'Testing {x}')
assert x > 0
# Simulated run:
test_values(10)
test_values(20)
Focus: @pytest.mark.parametrize('x', [10, 20])
Aha moment
import pytest
@pytest.mark.parametrize('chars', ['ab'])
def test_string(chars):
print(f'Chars: {chars}')
# Simulated run:
test_string('ab')
Prediction: How many times does this test run?
Common guess: Twice: once for 'a' and once for 'b'.
It runs only once. The list `['ab']` has exactly one item (the string 'ab'). pytest counts the items in the list, it does not split strings into characters.
Common mistakes
- Mismatched argument names: If the string says `'a, b'` but your test function takes `def test_func(x, y):`, pytest will crash. The names in the string must exactly match the function arguments.
- Missing the tuple structure: When testing multiple arguments, the list must contain tuples like `[(1, 2), (3, 4)]`. Writing a flat list like `[1, 2, 3, 4]` will fail.
Recall questions
- Explain @pytest.mark.parametrize in your own words, as if to a classmate.
- Why is parametrize better than using a normal for-loop inside a test function?
Understanding checks
Where is the bug in this test?
The arguments in the string ('x, y') do not match the function parameters (val1, val2).
The argument names declared in the `parametrize` string must perfectly match the variable names in the test function signature.
What is the final value of the global count after pytest finishes?
3
The test runs exactly once for each item in the list. There are three items, so the test runs three times, incrementing count to 3.
Practice tasks
Add a new test case
Given this code, add a third test case where `a=5`, `b=5`, and `total=10`.
Challenge
Write a parametrized test
Write a parametrized test named `test_type` that checks if `type(val) == int`. Use a single parameter `val` and run it with the values `10` and `20`.
Continue learning
Previous: Test discovery and naming conventions