Testing¶
INVA builds test-first: behaviour ships with its test in the same PR, and CI runs the suite on every push. A bug fix starts with a failing test.
Strategy by repo type¶
| Repo | Framework | What "tested" means |
|---|---|---|
Services (emma-platform, emma-gateway) |
unittest / pytest + coverage |
unit tests per module, integration tests behind env gates, coverage floor enforced |
Static site (inva-is) |
site checks + Lighthouse | link/format/accessibility/performance QA, not unit tests |
Infrastructure (inva-infrastructure) |
queue CI + --check |
schema/lint/CLI tests for tooling; ansible-playbook --check, tofu plan for changes |
Conventions (services)¶
- One test file per module —
tests/test_<module>.pymirrors the module. - Arrange / Act / Assert, asserting on outcomes not incidental detail.
- Dependency-gated skips: tests needing an optional dependency self-skip
when it is absent (
@unittest.skipUnless(...)), so the pure core stays runnable anywhere and the full suite runs in CI where the deps are installed. - No shared/production resources: database-backed tests self-skip without an explicit disposable DSN; never point a test at a live system.
- Determinism: inject time, clients and randomness — no real network or wall clock in a unit test.
Coverage¶
Coverage is measured on every run and gated in each repo's config
([tool.coverage.report] fail_under for Python). Do not lower the floor to
make a change pass — add the missing test. Raise the floor as integration
tests land for currently-uncovered surfaces (database adapters, server
entrypoints); landing those also lets relaxed type modules move into the strict
set (see coding standards).
The one command¶
make check runs every gate locally — the same set CI runs. If it is green, the
PR's checks will be too.