docs: add OpenAPI-first wiki (overview, components, use cases for templates/client/codegen, design, security, error handling, testing) and refresh lib docs index

This commit is contained in:
2026-09-15 22:29:05 +05:30
parent adeb02e162
commit b559323dfe
26 changed files with 1590 additions and 86 deletions

137
docs/wiki/07_testing.md Normal file
View File

@@ -0,0 +1,137 @@
# Testing — Smoke-First, Contract-First
Everything `openapi-first` ships is tested against **real specs, real handlers, and real HTTP** through FastAPI's `TestClient` and the bundled templates. There are no fakes of the library itself.
---
## 🧪 1. Suite Overview
```
tests/
├── conftest.py # fixtures: spec_file, routes_module, app, client
├── test_app.py # OpenAPIFirstApp: routes served, overrides, fail-fast
├── test_binder.py # bind_routes: opId resolution + missing-handler failures
├── test_loader.py # load_openapi: json/yaml, env resolution, validation
└── test_client.py # OpenAPIClient: opId→callable, params, error cases
```
Run with:
```bash
pytest # 23 tests, zero mocks of the library
pytest -q
pytest tests/test_loader.py
```
---
## 🏗️ 2. The Fixture Pattern
```python
# conftest.py (abridged)
@pytest.fixture
def spec_file(tmp_path):
path = tmp_path / "openapi.json"
path.write_text(json.dumps(SPEC), encoding="utf-8")
return str(path)
@pytest.fixture
def app(spec_file):
return OpenAPIFirstApp(
openapi_path=spec_file,
routes_module=routes_module(),
)
@pytest.fixture
def client(spec_file):
return OpenAPIClient(json.loads(Path(spec_file).read_text()))
```
---
## 🧪 3. What's Actually Asserted
### 3.1 App-level smoke
```python
def test_app_routes_served(spec_file):
app = OpenAPIFirstApp(openapi_path=spec_file, routes_module=routes)
client = TestClient(app)
assert client.get("/health").json() == {"status": "ok"}
```
### 3.2 Fail-fast (the heart)
```python
def test_app_missing_handler_fails_at_startup(spec_file):
with pytest.raises(MissingOperationHandler):
OpenAPIFirstApp(openapi_path=spec_file, routes_module=empty_routes)
```
### 3.3 Loader validation
```python
def test_loader_invalid_spec_fails():
with pytest.raises(OpenAPISpecLoadError):
load_openapi("broken.yaml")
```
### 3.4 Client contract drift
```python
def test_client_duplicate_operation_id_raises():
with pytest.raises(OpenAPIClientError):
OpenAPIClient(dup_spec)
```
---
## 🏛️ 4. Testing the Templates
Each bundled template ships its own test + in-memory store, so you get a runnable contract test the moment you scaffold:
```bash
openapi-first scaffold crud_app my-service
cd my-service
pytest -q
```
`test_crud_app.py` / `test_model_app.py` / `test_vet_app.py` exercise the full CRUD surface through `TestClient` — including `201`/`204` status codes, 404s, and (in `vet_app`) SSE streaming via `StreamingResponse`.
---
## 🕹️ 5. Quality Gates (CI)
The same gates the library itself must pass are what keep the docs honest:
| Gate | Purpose |
|------|---------|
| `black --check` | formatting parity |
| `ruff check` | lint hygiene |
| `mypy` | type safety (strict, `--disable-error-code` where intentional) |
| `pytest` | 23 tests, green |
| coverage | tracked via pytest-cov (HTML + XML + term) |
Run the whole gate locally:
```bash
black --check openapi_first tests
ruff check openapi_first tests
mypy openapi_first
pytest
```
---
## 💡 6. Testing Tips
- **Start from startup:** assert `OpenAPIFirstApp(...)` *raises* for the broken contracts — those are your most valuable tests
- **Client ↔ server:** smoke a client against the same spec the app was built from — one spec, two sides, zero drift
- **Templates are scaffolds:** their tests are copyable starting points, not canonical suites
- **No mocking of the library:** exercise loader → binder → app → client as a real pipeline
---
## Related
- [01 Overview](01_overview.md) · [02 Components](02_components.md) · [04 Error Handling](06_error_handling.md)