pytest-expected-json 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_expected_json/__init__.py +15 -0
- pytest_expected_json/fixture.py +102 -0
- pytest_expected_json/plugin.py +5 -0
- pytest_expected_json/py.typed +0 -0
- pytest_expected_json-0.1.0.dist-info/METADATA +204 -0
- pytest_expected_json-0.1.0.dist-info/RECORD +8 -0
- pytest_expected_json-0.1.0.dist-info/WHEEL +4 -0
- pytest_expected_json-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Pytest expected data fixture for loading test data from JSON files."""
|
|
2
|
+
|
|
3
|
+
from pytest_expected_json.fixture import (
|
|
4
|
+
ExpectedJsonConfig,
|
|
5
|
+
create_expected_json_config_fixture,
|
|
6
|
+
expected_data,
|
|
7
|
+
expected_json_config,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ExpectedJsonConfig",
|
|
12
|
+
"create_expected_json_config_fixture",
|
|
13
|
+
"expected_data",
|
|
14
|
+
"expected_json_config",
|
|
15
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Pytest fixture for loading expected test data from JSON files."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Literal, cast
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
JsonType = dict[str, Any] | list[Any] | str | int | float | bool | None
|
|
12
|
+
FixtureScope = Literal["function", "class", "module", "package", "session"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class ExpectedJsonConfig:
|
|
17
|
+
"""Configuration for the expected_data fixture."""
|
|
18
|
+
|
|
19
|
+
assets_dir: Path = Path("assets")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_expected_json_config_fixture(
|
|
23
|
+
config: ExpectedJsonConfig | None = None, *, scope: FixtureScope = "session"
|
|
24
|
+
) -> Callable[[], ExpectedJsonConfig]:
|
|
25
|
+
"""
|
|
26
|
+
Create a fixture that returns config used by the expected_data fixture.
|
|
27
|
+
|
|
28
|
+
Override this fixture in a project to provide custom configuration.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def fixture() -> ExpectedJsonConfig:
|
|
32
|
+
"""Provide configuration consumed by the expected_data fixture."""
|
|
33
|
+
return config or ExpectedJsonConfig()
|
|
34
|
+
|
|
35
|
+
decorated_fixture = pytest.fixture(scope=cast(Any, scope))(fixture)
|
|
36
|
+
return cast(Callable[[], ExpectedJsonConfig], decorated_fixture)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
expected_json_config = create_expected_json_config_fixture()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture()
|
|
43
|
+
def expected_data(
|
|
44
|
+
request: pytest.FixtureRequest, expected_json_config: ExpectedJsonConfig
|
|
45
|
+
) -> JsonType:
|
|
46
|
+
"""
|
|
47
|
+
Load the expected data from a JSON file based on the test location and name.
|
|
48
|
+
|
|
49
|
+
The fixture automatically constructs a filename from the test module
|
|
50
|
+
and function name. If a parametrized test is used, the parameter
|
|
51
|
+
is appended to the filename.
|
|
52
|
+
|
|
53
|
+
File naming convention:
|
|
54
|
+
{module_name}__{test_name}__{original_name}[@{param}].json
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
For test `test_health.py::test_get_health`, the fixture looks for:
|
|
58
|
+
tests/assets/saved/tests_app__test_health__test_get_health.json
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
request: Pytest request object containing test information.
|
|
62
|
+
expected_json_config: Fixture-provided configuration for asset lookup
|
|
63
|
+
and fallback behavior.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Parsed JSON data from the file, or the configured default value
|
|
67
|
+
if file not found.
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
config = expected_json_config
|
|
71
|
+
|
|
72
|
+
# Build filename from node id path, flattening path segments with "__".
|
|
73
|
+
node_id_path = request.node.nodeid.split("::", 1)[0]
|
|
74
|
+
if not node_id_path.endswith(".py"):
|
|
75
|
+
return {}
|
|
76
|
+
|
|
77
|
+
module_path = node_id_path[:-3]
|
|
78
|
+
path_parts = [part for part in module_path.split("/") if part]
|
|
79
|
+
if path_parts and path_parts[0] == "tests":
|
|
80
|
+
path_parts = path_parts[1:]
|
|
81
|
+
|
|
82
|
+
if not path_parts:
|
|
83
|
+
return {}
|
|
84
|
+
|
|
85
|
+
test_name = request.node.originalname
|
|
86
|
+
file_name = "__".join([*path_parts, test_name])
|
|
87
|
+
|
|
88
|
+
# Add parametrize id if present
|
|
89
|
+
if hasattr(request, "param"):
|
|
90
|
+
file_name += f"::{request.param}"
|
|
91
|
+
|
|
92
|
+
# Get the tests directory
|
|
93
|
+
file_path = request.config.rootpath / config.assets_dir / f"{file_name}.json"
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
if not file_path.exists():
|
|
97
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
98
|
+
|
|
99
|
+
with file_path.open(encoding="utf-8") as f:
|
|
100
|
+
return cast(JsonType, json.load(f))
|
|
101
|
+
except (FileNotFoundError, FileExistsError):
|
|
102
|
+
return {}
|
|
File without changes
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytest-expected-json
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A reusable pytest fixture for loading expected test data from JSON files
|
|
5
|
+
Author: Maxime MARTIN
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: fixture,json,pytest,testing
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Framework :: Pytest
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Requires-Python: <3.15,>=3.11
|
|
18
|
+
Requires-Dist: pytest>=7.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# pytest-expected-json
|
|
22
|
+
|
|
23
|
+
A reusable pytest fixture for loading expected test data from JSON files.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- 📋 Automatic file path resolution based on test location and name
|
|
28
|
+
- 🔧 Configurable assets directory and default return values
|
|
29
|
+
- 🎯 Support for parametrized tests
|
|
30
|
+
- 📦 Easy integration as a pytest plugin
|
|
31
|
+
- ✅ Type hints included
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### From local directory
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install -e /path/to/pytest-expected-json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### From another project
|
|
42
|
+
|
|
43
|
+
Once published, install via:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install pytest-expected-json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### Basic Setup
|
|
52
|
+
|
|
53
|
+
The fixture automatically registers as a pytest plugin. Add it to your dependencies in `pyproject.toml`:
|
|
54
|
+
|
|
55
|
+
```toml
|
|
56
|
+
dependencies = [
|
|
57
|
+
"pytest-expected-json>=0.1.0",
|
|
58
|
+
]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Using the Fixture
|
|
62
|
+
|
|
63
|
+
In your test files, use the `expected_data` fixture:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import pytest
|
|
67
|
+
|
|
68
|
+
def test_get_user(expected_data):
|
|
69
|
+
"""Test with expected data."""
|
|
70
|
+
# expected_data will automatically load from:
|
|
71
|
+
# tests/assets/saved/tests_app__test_users__test_get_user.json
|
|
72
|
+
result = get_user(1)
|
|
73
|
+
assert result == expected_data
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### File Naming Convention
|
|
77
|
+
|
|
78
|
+
The fixture automatically constructs filenames based on the test location:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
{module_name}__{test_file}__{test_name}[@{param}].json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Example:**
|
|
85
|
+
- Test file: `tests/tests_app/test_users.py`
|
|
86
|
+
- Test function: `test_get_user`
|
|
87
|
+
- Expected file: `tests/assets/saved/tests_app__test_users__test_get_user.json`
|
|
88
|
+
|
|
89
|
+
### Parametrized Tests
|
|
90
|
+
|
|
91
|
+
For parametrized tests, the parameter is appended to the filename:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
@pytest.mark.parametrize("expected_data", ["case1", "case2"], indirect=True)
|
|
95
|
+
def test_with_params(expected_data):
|
|
96
|
+
# Loads: tests/assets/saved/tests_app__test_users__test_with_params@case1.json
|
|
97
|
+
# Loads: tests/assets/saved/tests_app__test_users__test_with_params@case2.json
|
|
98
|
+
pass
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Configuration
|
|
102
|
+
|
|
103
|
+
You can configure the fixture behavior in your test conftest:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from pytest_expected_data.fixture import set_assets_dir, set_default_return
|
|
107
|
+
|
|
108
|
+
# Change the assets directory (default: "tests/assets/saved")
|
|
109
|
+
set_assets_dir("fixtures/expected_data")
|
|
110
|
+
|
|
111
|
+
# Change default return value when file not found (default: {})
|
|
112
|
+
set_default_return([])
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Or in `pytest.ini`:
|
|
116
|
+
|
|
117
|
+
```ini
|
|
118
|
+
[pytest]
|
|
119
|
+
# Configuration via environment or conftest
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Directory Structure
|
|
123
|
+
|
|
124
|
+
Create your test expected data files:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
tests/
|
|
128
|
+
├── assets/
|
|
129
|
+
│ └── saved/
|
|
130
|
+
│ ├── tests_app__test_users__test_get_user.json
|
|
131
|
+
│ ├── tests_app__test_users__test_list_users.json
|
|
132
|
+
│ └── tests_health__test_health__test_health_check.json
|
|
133
|
+
├── tests_app/
|
|
134
|
+
│ └── test_users.py
|
|
135
|
+
├── tests_health/
|
|
136
|
+
│ └── test_health.py
|
|
137
|
+
└── conftest.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
### Setup Development Environment
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cd pytest-expected-json
|
|
146
|
+
pip install -e ".[dev]"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Run Tests
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
pytest
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Run Tests with Coverage
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pytest --cov=src/pytest_expected_data --cov-report=html
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Code Quality
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Format code
|
|
165
|
+
black src tests
|
|
166
|
+
|
|
167
|
+
# Lint code
|
|
168
|
+
ruff check src tests
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## API Reference
|
|
172
|
+
|
|
173
|
+
### `expected_data(request: pytest.FixtureRequest) -> JsonType`
|
|
174
|
+
|
|
175
|
+
Pytest fixture that loads expected test data from a JSON file.
|
|
176
|
+
|
|
177
|
+
**Parameters:**
|
|
178
|
+
- `request`: Pytest fixture request object
|
|
179
|
+
|
|
180
|
+
**Returns:**
|
|
181
|
+
- Parsed JSON data (dict, list, str, int, float, bool, or None)
|
|
182
|
+
- Default empty dict `{}` if file not found (configurable)
|
|
183
|
+
|
|
184
|
+
**Raises:**
|
|
185
|
+
- `FileNotFoundError`: If JSON file doesn't exist (caught and returns default)
|
|
186
|
+
- `json.JSONDecodeError`: If JSON is invalid (caught and returns default)
|
|
187
|
+
|
|
188
|
+
### `set_assets_dir(assets_dir: str) -> None`
|
|
189
|
+
|
|
190
|
+
Configure the directory where expected data JSON files are stored.
|
|
191
|
+
|
|
192
|
+
**Parameters:**
|
|
193
|
+
- `assets_dir`: Relative path from the tests directory (default: `"tests/assets/saved"`)
|
|
194
|
+
|
|
195
|
+
### `set_default_return(default_value: JsonType) -> None`
|
|
196
|
+
|
|
197
|
+
Configure the default return value when expected data file is not found.
|
|
198
|
+
|
|
199
|
+
**Parameters:**
|
|
200
|
+
- `default_value`: Any JSON-serializable value (default: `{}`)
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pytest_expected_json/__init__.py,sha256=h8_mdPyHVus6nuWejU1DubRlVWFT5MfMNRvxLaFCqDY,363
|
|
2
|
+
pytest_expected_json/fixture.py,sha256=LdOD_gdpbyME3Q-w_xy0vOg3kmjZo8EyoJzXmqwTp4U,3239
|
|
3
|
+
pytest_expected_json/plugin.py,sha256=2t4fcjZ0DprgzxTnKgPiXQI9KCwJcY7CXpyFV5upif4,191
|
|
4
|
+
pytest_expected_json/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
pytest_expected_json-0.1.0.dist-info/METADATA,sha256=8n7WDmtiaDGZ4cpSxeWbRUGGz7JzE5I34nnLdgqt1Q8,4780
|
|
6
|
+
pytest_expected_json-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
7
|
+
pytest_expected_json-0.1.0.dist-info/entry_points.txt,sha256=kLtf5qx310n0fzyj0ouYMAVwF-dT70uLkY-dfyAjmH0,62
|
|
8
|
+
pytest_expected_json-0.1.0.dist-info/RECORD,,
|