Files
openapi-first/openapi_first/templates/crud_app/test_crud_app.py
Vishesh 'ironeagle' Bangotra a74e3d0d01 Introduce an OpenAPI-first HTTP client driven by the same specification
used for server-side route binding, and refactor documentation and
templates to treat the client as a first-class contract consumer.

Key changes:
- Add OpenAPI-first client module based on httpx
- Document client usage alongside server-side binder usage
- Update mkdocs navigation to include client documentation
- Refactor CRUD and model app templates to call APIs via operationId
  instead of hardcoded paths
- Align package documentation and public API surface with client support
- Clarify server/client dependency split (fastapi vs httpx)

This establishes strict symmetry between OpenAPI-driven server binding
and OpenAPI-driven client invocation, reinforcing OpenAPI as the single
source of truth on both sides of the contract.
2026-01-11 18:41:27 +05:30

117 lines
2.7 KiB
Python

"""
End-to-end tests for the OpenAPI-first CRUD example app.
These tests validate that all CRUD operations behave correctly
against the in-memory mock data store.
The tests assume:
- OpenAPI-first route binding
- In-memory storage (no persistence guarantees)
- Deterministic behavior in a single process
"""
from fastapi.testclient import TestClient
from main import app
from openapi_first.loader import load_openapi
from openapi_first.client import OpenAPIClient
client = TestClient(app)
spec = load_openapi("openapi.yaml")
client = OpenAPIClient(
spec=spec,
base_url="http://testserver",
client=client,
)
def test_list_items_initial():
"""Initial items should be present."""
response = client.list_items()
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
assert len(data) >= 2
ids = {item["id"] for item in data}
assert 1 in ids
assert 2 in ids
def test_get_item():
"""Existing item should be retrievable by ID."""
response = client.get_item(
path_params={"item_id": 1}
)
assert response.status_code == 200
item = response.json()
assert item["id"] == 1
assert "name" in item
assert "price" in item
def test_create_item():
"""Creating a new item should return the created entity."""
payload = {
"name": "Orange",
"price": 0.8,
}
response = client.create_item(
body=payload
)
assert response.status_code == 201
item = response.json()
assert "id" in item
assert item["name"] == payload["name"]
assert item["price"] == payload["price"]
# Verify it appears in list
list_response = client.list_items()
ids = {i["id"] for i in list_response.json()}
assert item["id"] in ids
def test_update_item():
"""Updating an item should replace its values."""
payload = {
"name": "Green Apple",
"price": 0.6,
}
response = client.update_item(
path_params={"item_id": 1},
body=payload,
)
assert response.status_code == 200
item = response.json()
assert item["id"] == 1
assert item["name"] == payload["name"]
assert item["price"] == payload["price"]
# Verify persisted update
get_response = client.get_item(
path_params={"item_id": 1}
)
updated = get_response.json()
assert updated["name"] == payload["name"]
assert updated["price"] == payload["price"]
def test_delete_item():
"""Deleting an item should remove it from the store."""
response = client.delete_item(
path_params={"item_id": 2}
)
assert response.status_code == 204
# Verify deletion
list_response = client.list_items()
ids = {item["id"] for item in list_response.json()}
assert 2 not in ids