chore: reorganize test files into domain-specific subdirectories under tests/

Split the monolithic test directory into three tiers (unit, api, e2e) with a path-mirroring directory structure. Added corresponding Makefile targets (test-unit, test-api, test-e2e) and updated all documentation references (CLAUDE.md, README.md, testing-cicd.html, testing-framework.html, testing-make.html) to reflect the new layout and naming conventions.
This commit is contained in:
2026-06-13 14:32:33 +00:00
parent 014c4c6bb3
commit 43f4011005
268 changed files with 20634 additions and 9206 deletions
+12 -5
View File
@@ -3,14 +3,21 @@
How DevPlace verifies itself: an end-to-end browser suite, in-process unit tests, and a load-testing rig, all driven through the project `Makefile`, measured for coverage, and promoted through automated DTAP streets. See also [Test framework and rules](/docs/testing-framework.html), [Load testing with Locust](/docs/testing-locust.html), [Running tests via make](/docs/testing-make.html), and [Coverage and CI/CD](/docs/testing-cicd.html).
## Two layers, one suite
## Three tiers, a directory tree that mirrors the path
The `tests/` directory holds the correctness suite: over 600 tests across 48 `test_*.py` files. Two styles live side by side and run under the same `pytest` invocation:
The `tests/` directory holds the correctness suite: 932 tests organised into three category directories by *what each test exercises*. Within each tier the **directory structure mirrors the path** - one segment per directory, the last segment is the file:
- **End-to-end (Playwright).** A real Chromium browser drives a real Uvicorn server. These cover anything a user sees or clicks: rendering, forms, navigation, modals, and JavaScript behavior.
- **In-process unit and API tests.** A FastAPI `TestClient` (or direct `asyncio` calls) exercises routers, data helpers, and JSON responses without a browser, for logic that has no UI surface.
- **`tests/api/` - HTTP integration tests.** `requests`/`httpx` drive a real Uvicorn server (`app_server`) and assert on status, JSON, and headers without a browser. **Organised by endpoint path.**
- **`tests/e2e/` - end-to-end (Playwright).** A real Chromium browser drives the same Uvicorn server, covering anything a user sees or clicks. **Organised by endpoint path.**
- **`tests/unit/` - in-process unit tests.** Pure tests over functions and data helpers (the `local_db` fixture or none), no running server. **Organised by the source module path** of the code under test.
Both styles share one fixture stack and one ephemeral SQLite database, so a single `make test` runs everything.
A test's tier is chosen by its fixtures: a browser fixture (`page`/`alice`/`bob`) makes it e2e; `app_server`/`seeded_db` or any HTTP call makes it api; `local_db`-only or no fixture makes it unit.
**api and e2e tests follow the endpoint's path:** each route segment becomes a directory and the final segment becomes the file, with `{param}` segments dropped and each segment lowercased + stripped of non-alphanumerics. So `GET /admin/ai-usage` becomes `tests/e2e/admin/aiusage.py`, `POST /auth/login` becomes `tests/api/auth/login.py`, and `GET /projects/{slug}/files/lines` becomes `tests/api/projects/files/lines.py`. A bare collection path that is also a parent of deeper paths uses `index.py` inside its own directory (`GET /posts` → `tests/e2e/posts/index.py`, beside `POST /posts/create` → `tests/e2e/posts/create.py`); `GET /` becomes `tests/<tier>/root.py`. Multiple HTTP verbs for one path share a single file.
**unit tests mirror the source module path:** tests for `devplacepy/utils.py` live in `tests/unit/utils.py`, and tests for `devplacepy/services/audit/store.py` live in `tests/unit/services/audit/store.py`.
Every directory is a Python package (`__init__.py`). Files are not `test_`-prefixed (the discovery glob is widened to `*.py`); test *functions* still start with `test_`. All three tiers share one fixture stack (the root `tests/conftest.py`) and one ephemeral SQLite database, so a single `make test` runs everything, while `make test-unit`, `make test-api`, and `make test-e2e` run a single tier.
## The load layer