Testing¶
patera.testing.PateraTestClient runs the application (including startup and shutdown hooks)
and sends requests through HTTPX. It needs the testing extra,
which also installs pytest and pytest-asyncio:
A first test¶
# tests/conftest.py
import pytest
from patera.testing import PateraTestClient
from app import App
@pytest.fixture
async def client():
async with PateraTestClient(App()) as c:
yield c
# tests/test_users.py
async def test_list_users(client):
res = await client.get("/api/v1/users/")
assert res.status_code == 200
The client offers get, post, put, patch, delete, head, options and request, which
all accept the usual HTTPX keyword arguments such as json=, headers= and files=.
The async context manager runs the lifespan. A bare HTTPX ASGI transport does not run startup and shutdown hooks.
Configure pytest¶
# pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
Run the tests¶
uv run patera test # loads .env.test if present
uv run patera test -k login -q # pytest options in any order
uv run patera test -- -x # everything after -- goes to pytest unchanged
uv run pytest # plain pytest
patera test --env-file FILE loads another environment file, which must exist.
Good practice¶
- Set test configuration and environment variables before constructing the app.
- Use a fresh app and isolated databases, files and caches for independent tests.
- Test production error behaviour with
DEBUGdisabled when asserting generic500bodies. - Cover input failures, authorization, transaction commit/rollback, response models and lifecycle cleanup.
- Mock external SMTP, HTTP and AI transports instead of sending real requests.
- Use a socket harness for WebSockets and isolated argv/output/filesystem for CLI commands.