Skip to content

Commit 0281ab2

Browse files
committed
Added example and README
1 parent 06bd93c commit 0281ab2

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Package to use type annotations for parametrization in pytest
2+
3+
This package allows the declaration of parametrization using type annotations and definition of test cases using a
4+
decorator.
5+
6+
The primary reason of using this package over the standard `pytest.mark.parametrize` is readability and maintainability
7+
of test cases especially if many test cases are defined for a single test function.
8+
In addition, error messages are more informative compared to those provided by `pytest.mark.parametrize`.
9+
10+
## Install pytest-parametrization-annotation
11+
12+
```shell
13+
pip install pytest-parametrization-annotation
14+
```
15+
16+
## Usage
17+
18+
### Defining a test function parameter as parametrized
19+
20+
To define a parameter as parametrized, use the `Parametrized` class or an instance of the `Parametrized` class as an
21+
annotation.
22+
23+
```python
24+
from typing import Annotated
25+
from pytest_parametrization_annotation import Parametrized
26+
27+
28+
# Both definitions are treated the same
29+
def test(a: Annotated[int, Parametrized], b: Annotated[int, Parametrized()]) -> None:
30+
...
31+
```
32+
33+
By default, parameters annotated in this way are treated as direct parameters.
34+
To define a parameter as indirect, use the `indirect` argument when instantiating the `Parametrized` class.
35+
36+
```python
37+
from typing import Annotated
38+
from pytest_parametrization_annotation import Parametrized
39+
40+
41+
def test(a: Annotated[int, Parametrized(indirect=True)]) -> None:
42+
...
43+
```
44+
45+
In addition, the `Parametrized` class provides to methods to define default values, `default` and `default_factory`.
46+
47+
```python
48+
from typing import Annotated
49+
from pytest_parametrization_annotation import Parametrized
50+
51+
52+
def test(
53+
a: Annotated[int, Parametrized(default=1)],
54+
b: Annotated[str, Parametrized(default_factory=lambda: "Hello World!")]
55+
) -> None:
56+
...
57+
```
58+
59+
## Defining test cases
60+
61+
To define test cases, use the `case` marker.
62+
Each parametrized argument must be reflected as keyword in the case marker.
63+
64+
```python
65+
from typing import Annotated
66+
import pytest
67+
from pytest_parametrization_annotation import Parametrized
68+
69+
70+
@pytest.mark.case(a=1)
71+
def test(a: Annotated[int, Parametrized]) -> None:
72+
...
73+
```
74+
75+
If a parametrized argument is missing from the case marker, the test suit will fail and a detailed error message will be provided.
76+
77+
```shell
78+
examples/test_basic.py::test_addition | Case number 1: Failed to populate because the parameter 'b' is not provided and default is not configured.
79+
```
80+
81+
Every case marker defines a single test case.
82+
To define multiple test cases, use multiple case markers.
83+
84+
```python
85+
from typing import Annotated
86+
import pytest
87+
from pytest_parametrization_annotation import Parametrized
88+
89+
90+
@pytest.mark.case(a=1)
91+
@pytest.mark.case(a=2)
92+
@pytest.mark.case(a=3)
93+
def test(a: Annotated[int, Parametrized]) -> None:
94+
...
95+
```
96+
97+
98+
Optionally a case can be named by providing the first positional argument to the case marker.
99+
If this is not provided the default pytest naming scheme is used.
100+
101+
```python
102+
from typing import Annotated
103+
import pytest
104+
from pytest_parametrization_annotation import Parametrized
105+
106+
107+
@pytest.mark.case("Example", a=1)
108+
def test(a: Annotated[int, Parametrized]) -> None:
109+
...
110+
```

examples/test_basic.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from typing import Annotated
2+
3+
import pytest
4+
from pytest_parametrization_annotation import Parametrized
5+
6+
7+
@pytest.mark.case(
8+
a=1,
9+
b=2,
10+
expected=3,
11+
)
12+
def test_addition(
13+
a: Annotated[int, Parametrized],
14+
b: Annotated[int, Parametrized],
15+
expected: Annotated[int, Parametrized],
16+
) -> None:
17+
assert a + b == expected

examples/test_indirect.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
3+
from typing import Annotated, TYPE_CHECKING
4+
5+
import pytest
6+
from pytest_parametrization_annotation import Parametrized
7+
8+
if TYPE_CHECKING:
9+
from _pytest.fixtures import FixtureRequest
10+
11+
12+
@pytest.fixture
13+
def doubled(request: FixtureRequest) -> int:
14+
return request.param * 2
15+
16+
17+
@pytest.mark.case(
18+
doubled=1,
19+
b=2,
20+
expected=4,
21+
)
22+
def test_addition(
23+
doubled: Annotated[int, Parametrized(indirect=True)],
24+
b: Annotated[int, Parametrized],
25+
expected: Annotated[int, Parametrized],
26+
) -> None:
27+
assert doubled + b == expected

0 commit comments

Comments
 (0)