test(fastapi): add pytest-benchmark suite for the FastAPI integration layer#178
test(fastapi): add pytest-benchmark suite for the FastAPI integration layer#178tmgbedu wants to merge 1 commit into
Conversation
… layer Benchmarks Application boot + provider register/boot, Router.get/post and resource() CRUD expansion, and request handling through TestClient — each paired with a raw-FastAPI/APIRouter baseline for overhead comparison. Deselected by default via the new "benchmark" marker so they stay out of the coverage-gated test run; opt in with `pytest -m benchmark`.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
tmgbedu
left a comment
There was a problem hiding this comment.
Code Review — APPROVE ✅
Reviewed the full diff and independently reproduced every claim in the test plan. Clean, well-scoped benchmark suite with fair baselines and correct gating. No blockers.
Benchmark quality & fair baselines ✔
Every framework hot path is paired with an apples-to-apples raw baseline so overhead reads as a ratio:
- Boot —
Application(default providers)andApplication(+FastAPIProvider)measured against a rawFastAPI()floor, so the framework's register/boot overhead is isolated from FastAPI's own cost. - Router single route —
Router().get()vsAPIRouter().add_api_route(); both include object construction, so it's a fair delta. - resource() expansion —
Router().resource("posts", PostController)vs hand-registering the same 7 CRUD routes onAPIRouter— measures exactly the expansion overhead. - Request handling — in-process
TestClientGET on trivial JSON endpoints, router-based vs raw-FastAPI, plus aresource()path-param route (/posts/1) exercising Starlette path matching. Client fixtures are module-scoped so setup cost isn't folded into the per-request timing.
Gating — correct, does not touch normal CI ✔
benchmarkmarker registered in[tool.pytest.ini_options].markers(no strict-marker warnings).addopts = "-m 'not benchmark'"deselects benchmarks by default; a command-line-m benchmarkoverrides it. Verified:pytest tests/fastapi→ 117 passed, 10 deselectedpytest -m benchmark tests/fastapi/benchmarks→ 10 passedpytest --ignore=.../postgres --cov→ 1833 passed, 7 skipped, 10 deselected, coverage 79.87% (gate 68%) — unaffected.
Determinism / no flakiness ✔
No sleeps, no network (TestClient is in-process ASGI), no live DB, no wall-clock/timing assertions (pytest-benchmark only records). The boot file's restore_container_instance fixture correctly restores the Container singleton that Application() mutates.
Scope & conventions ✔
- No core framework abstractions modified — changes limited to
pyproject.toml(dev dep + marker/addopts),uv.lock, and newtests/fastapi/benchmarks/files. asyncio_mode = "auto"preserved; benchmark tests are sync (correct — thebenchmarkfixture is sync-only), clean structure.ruff checkclean on the new files and pyproject.
Non-blocking observations (optional)
- Request-handling absolute numbers include
TestClient/ASGI transport overhead, but since both baseline and framework paths share it, the ~1.01–1.08x ratios correctly show negligible wrapper overhead — which is the intent. Fine as-is; a one-line comment noting that the ratio (not absolute μs) is the signal would help future readers. test_boot_default_providersincludes.envdisk reads each round; consistent and part of real boot cost, so not a flakiness concern.
Approving. (Posted as a comment — GitHub blocks self-approve on the authoring account; verdict is APPROVE.)
Summary
pytest-benchmarkas a dev dependency forfastapi-startkit.Applicationboot + provider register/boot (default providers, withFastAPIProvider, vs rawFastAPI())Router.get()andRouter.resource()CRUD expansion (vs hand-registering the same routes onAPIRouter)TestClienton trivial JSON GET endpoints, including a path-param resource routetmp_path-scoped.benchmarkmarker and are deselected by default (addopts = "-m 'not benchmark'"inpyproject.toml), so they don't slow down or affect the coverage-gated CI run. Run them explicitly with-m benchmark.Run command
Sample results table
Test plan
uv run pytest tests/fastapi -q— 117 passed, 10 deselected (benchmarks excluded by default)uv run pytest -m benchmark tests/fastapi/benchmarks— 10 passed, results table generateduv run pytest --ignore=tests/masoniteorm/postgres --cov --cov-report=term-missing— 1833 passed, coverage 79.87% (gate: 68%), unaffecteduv run ruff check— clean