-
Notifications
You must be signed in to change notification settings - Fork 2
Technical Testing
pytest # everything
pytest incidents/tests/ # one app
pytest incidents/tests/test_models.py # one file
pytest -k "custody" # by name
pytest --co # collect only, run nothing
pytest -n auto # parallel (pytest-xdist)
pytest --cov --cov-report=term-missing # with coveragepytest.ini pins DJANGO_SETTINGS_MODULE=core.settings_test, so there is
nothing to export. Those settings use an in-memory SQLite database, MD5 password
hashing, an in-memory channel layer and a local-memory cache : the suite needs
neither PostgreSQL nor Redis.
The test settings disable migrations, so Django builds the schema directly from the current models. That skips roughly 150 historical migrations and cuts start-up by an order of magnitude, but it also skips the data migrations that seed permissions, system groups, lifecycles and risk criteria.
conftest.py puts that back : a session-scoped django_db_setup fixture
recreates the permissions and system groups once, after the schema exists. If
you add a data migration that seeds reference rows the suite depends on, it
needs a matching line there, or the tests will pass locally against a stale
database and fail on a fresh one.
The trade-off has a second consequence worth knowing : the suite does not
exercise the migrations. A migration that is broken will pass CI and fail on
deployment. Run python manage.py migrate against a scratch PostgreSQL database
before tagging a release.
Every app has a tests/ package with the same two kinds of file.
<app>/tests/
├── factories.py factory-boy factories, one per model
├── test_models.py validation, computed fields, lifecycle side effects
├── test_views.py the web surface : permissions, filtering, HTMX partials
├── test_api.py the REST surface : contract, permissions, tenancy
└── test_*.py one file per behaviour worth isolating
Use the factories. They set the required fields, respect the lifecycle's initial step and generate references, so a test that builds a model by hand is usually a test that will break when a field becomes required.
A feature is not tested because it has a test; it is tested when the things that would be embarrassing to get wrong are pinned down. For this platform that means, in order:
- The permission. An unauthorised caller is refused, on the web view, the REST endpoint and the MCP tool. Three surfaces, three assertions.
- The tenancy. A user outside the scope does not see the record, including through a child entity or the generic history endpoint.
- The lifecycle. The transitions that should be allowed are, the ones that should not are refused with the right status, and a required comment is actually required.
-
The contract. Read-only fields cannot be written. Append-only registers
answer
405onPUT/PATCH/DELETE. A computed field is not writable. - The behaviour. Whatever the feature actually does.
.github/workflows/tests.yml runs on every push to main and every pull
request:
ruff check .-
python manage.py compilemessages(a duplicatemsgidfails here) pytest -x -v --tb=short --cov --cov-report=term-missing
.github/workflows/docs.yml adds the documentation gate : the generated
reference pages must be current, and every internal documentation link must
resolve. See documentation.md.
-x means the first failure stops the run, so read the first failure rather
than the last line.
ruff check . # what CI runs
ruff check --fix . # apply the safe fixesThe configuration lives in pyproject.toml.
Built from docs/ at v0.36.0. Edits made here are overwritten by the next release : open a pull request against the source instead.
- Administration
- Ask Cairn
- Assets and suppliers
- Compliance
- The dashboard
- Finding your way
- Getting started
- Incidents
- How records move
- Organisational context
- Reports and management review
- Risks
- Trust Center
- Architecture
- Configuration
- Contributing
- The documentation system
- Installation
- Internationalisation
- Operations
- Release process
- Security
- Testing
- Adding an assistant provider
- Adding a dashboard widget
- Adding a domain entity
- Declaring a lifecycle
- Adding an MCP tool
- Adding a REST endpoint
- Adding a report
- Interface conventions
- Dashboard widgets
- Lifecycles
- MCP tools
- MCP tool parameters : Assets
- MCP tool parameters : Compliance
- MCP tool parameters : Governance and context
- MCP tool parameters : General
- MCP tool parameters : Incidents
- MCP tool parameters : Reports and management review
- MCP tool parameters : Risks
- MCP tool parameters : System and administration
- MCP tool parameters : Trust Center
- Management commands
- Models
- Permissions
- REST endpoints
- Environment variables
- MCP server
- REST API
- Assistant module (Ask Cairn)
- Module 0: User Management and Access Control
- Module 1: Context and Organization
- Module 2: Asset Management
- Module 3: Compliance
- Module 4: Risk Management
- Module 4 bis - EBIOS Risk Manager
- Module 5 : Trust Center
- Module 6 : Security Incident Management
- Management review : ISO 27001:2022 compliance (clause 9.3)