90 lines
4.2 KiB
Markdown
90 lines
4.2 KiB
Markdown
---
|
||
trigger: always_on
|
||
---
|
||
|
||
## General Principles
|
||
- Write unit tests for new features prior to implementing the feature.
|
||
- Write unit tests for utilities and components.
|
||
- Maintain 100% test coverage (backend). Frontend coverage threshold follows CI config (≥90% or 100% for symmetry).
|
||
- Unit tests should never make external calls. Integration tests may call externals.
|
||
- Minimize fixtures for generating inputs; prefer explicit inline inputs/expectations.
|
||
- Tests should be written as functions (avoid class-based tests).
|
||
- Use descriptive, intention-revealing names (e.g., `isCreated`, `hasError`) and prefer iteration/modularization over duplication.
|
||
|
||
## Test Structure
|
||
|
||
### Top-level Layout
|
||
- `tests/unit/` for pure unit tests (no external I/O).
|
||
- `tests/integration/` for tests allowed to hit external services.
|
||
|
||
### Granular Python Unit Test Organization
|
||
1. Use a directory per module under test (e.g., `tests/unit/app/services/estimating/`).
|
||
2. Within that directory, use a file per function under test (e.g., `test_calculate_estimate.py`).
|
||
3. Keep unit and integration tests in separate trees: `tests/unit/` and `tests/integration/`.
|
||
|
||
### Naming and Scope
|
||
- Only test functionality in the module under test; don’t re-test validation or logic implemented elsewhere.
|
||
- Do not introduce coverage-only test files (e.g., files named with “additional_coverage”, “remaining_branches”, “misc_coverage”).
|
||
- When adding a new test file, name it by feature or unit under test (e.g., `test_service_delete_update.py`).
|
||
|
||
## Backend (FastAPI) Testing
|
||
|
||
### Framework
|
||
- Pytest
|
||
|
||
### Coverage and Practices
|
||
- Prefer tests over no-cover.
|
||
- Avoid `# pragma: no cover` except in strictly justified cases:
|
||
- Optional dependency branches or platform guards
|
||
- Defensive/unreachable paths in supported environments
|
||
- Use `pytest-mock`’s `mocker` fixture for mocking.
|
||
- Use monkeypatches to control `time.sleep`, `random.random`, etc., to keep tests fast/deterministic.
|
||
- For network-like behavior, write light fakes with only the attributes used by the code under test.
|
||
- If a safety guard exists (e.g., a best-effort `close()`), add a micro-test to exercise it.
|
||
|
||
### Commands
|
||
- Full suite (CI-like): `bash scripts/ci/backend-test.sh`
|
||
- Ad-hoc (from `backend/`):
|
||
- All tests (with dev extras): `uv run --with .[dev] -m pytest`
|
||
- With coverage: `uv run --with .[dev] -m pytest --cov=app --cov-report=term-missing`
|
||
- Single test/file: `uv run --with .[dev] -m pytest app/tests/unit/path/to/test_file.py::test_case`
|
||
|
||
### Notes
|
||
- Dev extras defined under `[project.optional-dependencies].dev` in `backend/pyproject.toml` and include `pytest`, `pytest-cov`.
|
||
- Pytest config lives under `[tool.pytest.ini_options]` in `backend/pyproject.toml` (e.g., `testpaths = ["app/tests"]`).
|
||
- Quick run without extras (no coverage): `uv run -m pytest` (no `pytest-cov`).
|
||
|
||
## Frontend (React or React Native) Testing
|
||
|
||
### Framework
|
||
- Jest + Testing Library (React) or Jest + React Native Testing Library (React Native)
|
||
|
||
### Mocking Guidance
|
||
- Avoid mocking React/React Native primitives unless necessary.
|
||
- Mock network via MSW.
|
||
|
||
### Commands
|
||
- Full suite (CI-like): `bash scripts/ci/frontend-test.sh`
|
||
- Ad-hoc (from `frontend/`):
|
||
- npm: `npm run lint` then `npm test -- --coverage`
|
||
- pnpm: `pnpm run lint` then `pnpm test -- --coverage`
|
||
|
||
## End-to-End (E2E) Testing
|
||
- Implement E2E tests for critical flows.
|
||
- Choose an appropriate framework based on the frontend:
|
||
- Web (React): Playwright or Cypress
|
||
- React Native: Detox
|
||
- Keep E2E focused on user-critical paths; avoid duplicating unit/integration coverage.
|
||
|
||
## CI Expectations and Consistency
|
||
- CI runs from `.gitea/workflows/`.
|
||
- Required checks:
|
||
- Backend: ruff, mypy, tests with coverage ≥100%.
|
||
- Frontend: eslint, jest with coverage thresholds (≥90% or 100% for symmetry).
|
||
- No merges to main without green pipelines.
|
||
- Use `scripts/ci/*` to mirror CI logic locally.
|
||
|
||
## Development Phase Testing (Pre-deployment)
|
||
- Update tests in the same PR when API contracts change (request/response shapes, validation, or status codes).
|
||
- Refresh example payloads in schemas and test fixtures together to prevent drift.
|
||
- Prefer targeted API integration tests for critical endpoints to validate schema and docs alignment. |