Skip to content
Aabha AI Academy

Stage 9 · L44

Own fixtures and choose meaningful test boundaries

Core · original Session 9

Choose a test boundary that matches the claim. Pure validation tests establish conversion/constraints. ASGI/TestClient tests establish the app contract. A real Uvicorn connection establishes TCP serving. A PostgreSQL fixture establishes stored constraints, isolation and committed effects. A deterministic HTTP transport establishes classified provider failures; one real local provider establishes an actual outbound HTTP boundary.

Fixtures own their resource lifetimes. The runner creates a unique internal network, a tmpfs PostgreSQL instance and a random synthetic credential, then removes exactly its owned containers/network in finally. Test URLs are guarded by the fixture database/host prefix. No .env or existing service connection is loaded; SQLite is not substituted for PostgreSQL behavior.

An app transport does not automatically run lifespan. Use TestClient as a context manager or explicitly enter app.router.lifespan_context for ASGITransport. Shared clients and engine cleanup must be established, not assumed. The observation test demonstrates the explicit async lifespan boundary.

Patch or override where the collaborator is used, and restore it in finally. The provider fixture patches equipment.api.SessionLocal, the actual import boundary used by current identity/preparation. The query-count fixture observes the same engine selected by its dependency override. Mocking a different module or counting another engine can make a test pass while bypassing the intended evidence.

Baseline checks exercise completed guided behavior. Transfer checks specify the still-unfinished independent task. A starter's expected transfer failure is not an application regression; a solution must pass both. Passing a toy dictionary would not establish an API/database lab, so these snapshot tests actually issue HTTP and inspect independent PostgreSQL sessions.

Arrange–Act–Assert gives a test a readable causal order. Arrange supplies the owned database/app/client and chosen input; Act makes the request or calls the operation; Assert compares its public outcome and protected effects with the contract. Avoid assertions that merely repeat implementation labels. A missing/forbidden response should be accompanied by a stored or outbound no-effect observation when that is the claim.

A stub supplies a chosen response, a spy records how a collaborator was called, and a mock combines substitution with configured expectations checked by the test. The local HTTP MockTransport may act as a stub while a calls list acts as a spy; asserting the expected path/count makes that collaborator expectation explicit. The terms describe roles in the test, not whether the object happens to have Mock in its library name.

Pure model: validation only; ASGI: application HTTP contract; Uvicorn: actual loopback TCP; PostgreSQL: real stored effects; Local provider: actual outbound HTTP
Pure model: validation only; ASGI: application HTTP contract; Uvicorn: actual loopback TCP; PostgreSQL: real stored effects; Local provider: actual outbound HTTP

Follow the running code

Focused lesson example; see the end-of-stage capstone for the cumulative app · stage 09

Arrange: owned app/fixture and expected provider response
Act: issue one HTTP request
Assert: status/public output plus protected effects

Stub: supplies a chosen result
Spy: records calls/arguments
Mock: configured collaborator checked against expectations

Predict and observe this focused example using the concepts explained above. Its boundary is stated in the focused answer.

Guided lab

  1. Read the explanation and predict the focused example’s outcome.
  2. Classify the local provider response function, captured calls and assert-count check. Explain what an authorization override fails to prove.
  3. Compare the observed outcome with the focused answer and state its boundary.

Expected: The response supplier is a stub; the call list is a spy; using configured expectations/assertions makes the substituted collaborator a mock in that test. Arrange establishes owned resources, Act performs the behavior, Assert checks outcomes/effects. An identity/scope override proves wiring, not real JWT/authorization. Lifespan and patch-at-use must be explicit; savepoint isolation is taught next.

  • An unused patch, missing lifespan or SQLite substitution can invalidate a PostgreSQL/HTTP claim.

Focused exercise and answer

Complete this focused exercise before reading its answer. The full native transfer is introduced only at the end of the stage.

Your transfer task: Classify the local provider response function, captured calls and assert-count check. Explain what an authorization override fails to prove.

  1. Classify the local provider response function, captured calls and assert-count check. Explain what an authorization override fails to prove.
Inspect the matching answer

This answer addresses the focused exercise above; the cumulative implementation is shown only after the stage prerequisites.

The response supplier is a stub; the call list is a spy; using configured expectations/assertions makes the substituted collaborator a mock in that test. Arrange establishes owned resources, Act performs the behavior, Assert checks outcomes/effects. An identity/scope override proves wiring, not real JWT/authorization. Lifespan and patch-at-use must be explicit; savepoint isolation is taught next.

Check your reasoning

Does a mock rollback assertion prove database rollback?

Show the explanation

No. It proves that a call was made; durable rollback needs an actual database failure and fresh-session inspection.

Reading progress

54 lessons remain open to guests. Marking a lesson read records reading only; it does not award assessment credit or a certificate.

Device reading marks require browser storage. Reading is always available.

Sign in or create an account to save separate account progress. Your current page is kept.