Testing Guide
Owner: Engineering Last reviewed: 2026-Q2
This guide defines how we write and run tests in this repo.
Principles
- Test behaviour, not implementation. Verify what the code does, not how it does it.
- Only use the public interface. Do not reach into internals to verify behaviour.
- Do not test what the type system guarantees. Focus on runtime behaviour, not type correctness.
- Cover edge cases and error paths. Include invalid input, unauthorized requests, missing resources, and failure scenarios, not just the happy path.
- Name tests descriptively. Use the pattern
test_<scenario>_<expected_outcome>, for exampletest_upload_file_without_auth_returns_401. - Use pytest with
httpx.AsyncClientfor endpoint tests. Mock all external dependencies such as Azure Blob Storage, Clerk, and OpenAI so tests never hit real services.
Backend
Backend tests live under backend/py/tests.
- Route tests belong in
backend/py/tests/test_routes. - Service tests belong in
backend/py/tests/test_services. - Core/auth tests belong in
backend/py/tests/test_core. - Shared fixtures and helpers live in
backend/py/tests/conftest.pyandbackend/py/tests/helpers.py.
Run from backend/py:
pytest tests/
pytest tests/test_routes/
pytest tests/test_services/Use route tests for request/response contracts, dependency wiring, status codes, and auth boundaries. Use service tests for business rules, data access, ranking, sharing, permission decisions, and edge cases.
External Dependencies
- Mock Clerk JWT/JWKS behavior unless the test is explicitly about token verification.
- Mock Azure Blob Storage, Azure OpenAI, Azure Vision, Azure Document Intelligence, and network calls.
- Keep tests deterministic: no real credentials, no real cloud resources, no clock-sensitive assertions without fixed time.
Database And Migrations
- Add migration tests or model-mapping tests when schema changes affect ORM mappings, cascades, ownership, or permissions.
- Prefer additive, backward-compatible migrations. Document destructive migrations and rollback expectations in the PR.
- Run Alembic locally when changing models:
alembic upgrade headFrontend
- Always run
npm run lintandnpm run buildfromfrontendfor frontend changes. - Prefer component or integration tests for complex UI states, forms, drag/drop behavior, permission-sensitive rendering, and error handling.
- Regenerate Orval clients after OpenAPI changes and do not hand-edit generated files.
- See
frontend-ux-standards.mdfor UI state and accessibility expectations.
Run from frontend:
npm run lint
npm run build
npm run orvalReview Expectations
- Every behavior change should include a test unless the change is documentation-only, generated-only, or explicitly impractical.
- Risky changes need broader coverage: auth, authorization, migrations, sharing, file upload, billing/entitlements, AI/provider calls, and data deletion.
- PR descriptions should state what was tested locally and which external dependencies were mocked.