Skip to content

Parametrize

The parametrize tag allows us to run the same test with several different inputs.

This works like pytest's parametrize decorator.

Basic Usage

First, here is a small example:

test.py
1
2
3
4
5
import karva

@karva.tags.parametrize("a", [1, 2, 3])
def test_function(a: int):
    assert a > 0

Running uv run karva test will run test_function three times, once for each value of a.

Multiple Variables

We can also parametrize multiple arguments:

test.py
1
2
3
4
5
import karva

@karva.tags.parametrize(("a", "b"), [(1, 4), (2, 5), (3, 6)])
def test_function(a: int, b: int):
    assert a > 0 and b > 0

Like pytest, we can put the arguments in a single string, separated by ",":

test.py
1
2
3
4
5
import karva

@karva.tags.parametrize("a,b", [(1, 4), (2, 5), (3, 6)])
def test_function(a: int, b: int):
    assert a > 0 and b > 0

Parametrize with Fixtures

We can also mix fixtures and parametrize:

test.py
1
2
3
4
5
6
7
8
9
import karva

@karva.fixture
def b() -> int:
    return 1

@karva.tags.parametrize("a", [1, 2])
def test_function(a: int, b: int):
    assert a > 0 and b > 0

Each parametrized variant receives the fixture value alongside the parametrized arguments.

Multiple Parametrize Tags

We can also use multiple decorators, allowing us to test more scenarios. This will result in a cartesian product of the parametrize values.

test.py
1
2
3
4
5
6
import karva

@karva.tags.parametrize("a", [1, 2])
@karva.tags.parametrize("b", [1, 2])
def test_function(a: int, b: int):
    assert a > 0 and b > 0

This runs test_function four times with all combinations of a and b.

IDs

Use ids to give parameter sets stable, readable names:

test.py
1
2
3
4
5
6
7
8
9
import karva

@karva.tags.parametrize(
    "card,expected",
    [(valid_card, "paid"), (expired_card, "declined")],
    ids=["valid-card", "expired-card"],
)
def test_checkout(card, expected):
    assert checkout(card) == expected

ids can also be a function. It is called for each parameter value, and returned parts are joined with -:

test.py
1
2
3
4
5
6
7
8
9
import karva

@karva.tags.parametrize(
    "status,expected",
    [("paid", True), ("declined", False)],
    ids=lambda value: value.upper() if isinstance(value, str) else None,
)
def test_status(status, expected):
    assert is_successful(status) is expected

IDs combine with - when multiple parametrize tags are stacked.

Use id on karva.param when each row should carry its own name:

test.py
1
2
3
4
5
6
7
8
import karva

@karva.tags.parametrize("card,expected", [
    karva.param(valid_card, "paid", id="valid-card"),
    karva.param(expired_card, "declined", id="expired-card"),
])
def test_checkout(card, expected):
    assert checkout(card) == expected

The ID appears in output and failure reports and provides a stable exact filter:

Bash Session
1
uv run karva -E 'test(="test::test_checkout(expired-card)")'

Params

You can use karva.param (similar to pytest.param) to attach tags to individual parameter sets:

test.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import karva

@karva.tags.parametrize("input,expected", [
    karva.param(2, 4),
    karva.param(4, 17, tags=(karva.tags.skip,)),
    karva.param(5, 26, tags=(karva.tags.expect_fail,)),
    karva.param(6, 36, tags=(karva.tags.skip(True),)),
    karva.param(7, 50, tags=(karva.tags.expect_fail(True),)),
])
def test_square(input, expected):
    assert input ** 2 == expected

Pytest

You can also still use @pytest.mark.parametrize:

test.py
1
2
3
4
5
import pytest

@pytest.mark.parametrize("a", [1, 2])
def test_function(a: int):
    assert a > 0