Parametrized Tests

RoadmapsPython Backend

Scenario

You need to test an email validator with 10 different valid emails and 10 invalid ones. You copy-paste the test 20 times.

Mental model

Parametrization is a loop for your tests. Instead of writing one test per scenario, you write the test logic once and feed it a table of inputs and expected outputs.

Deep dive

Pytest's `@pytest.mark.parametrize` decorator allows you to define multiple sets of arguments for a single test function.

When pytest runs, it treats each parameter set as an independent, standalone test. If one input fails, the others will still run.

Code examples

Repetitive testing

def test_is_valid_email_1():
    assert is_valid('test@example.com') is True

def test_is_valid_email_2():
    assert is_valid('invalid') is False

This approach scales poorly as the number of test cases increases.

Parametrized test

import pytest

@pytest.mark.parametrize("email, expected", [
    ('test@example.com', True),
    ('invalid', False),
    ('user@sub.domain.com', True),
])
def test_is_valid_email(email, expected):
    assert is_valid(email) == expected

The decorator unpacks each tuple into the test function arguments. Pytest reports this as 3 separate test cases.

Common mistakes

Recall questions

Questions & answers

How would you test an API endpoint that filters by status, ensuring it works for 'active', 'pending', and 'archived'?

I would write a single test function that makes a request to the endpoint, decorated with `@pytest.mark.parametrize('status', ['active', 'pending', 'archived'])`.

What happens if we stack two `@pytest.mark.parametrize` decorators on a single test?

Pytest will generate the cartesian product (all combinations) of both parameter sets.

Continue learning

Previous: Pytest Basics and Fixtures

Return to Python Backend Roadmap