Skip to main content

Build and test

A build is only useful if it is reproducible and a test is only useful if it fails when it should. This standard defines both — the automation chain, the test layers, and the gates that stop a change.

The standard. A reproducible build and test chain that turns a commit into a deployment-ready artefact, with gates that stop a change rather than merely reporting on it.

Why automate​

Builds. Consistency (the same inputs produce the same artefact), speed, early integration feedback, removal of manual error, and scaling without a proportional increase in effort.

Tests. Early defect detection, enforced quality, confidence that only tested code reaches production, unattended execution, and coverage across configurations that manual testing cannot reach.

The automation chain​

source → build → unit test → static analysis → package → artefact registry
│
integration test ◄─────┘
│
deploy to environment
StepRuns onProduces
Source checkoutEvery push and PR—
BuildEvery push and PRCompilation output
Unit testsEvery push and PRTest report, coverage
Static analysisEvery push and PRQuality gate result
Security scanEvery push and PRDependency and secret findings
PackageMerge to a protected branchVersioned artefact
Integration testMerge to dev or stageEnvironment-verified result
PublishMerge to mainImmutable artefact in registry

Reproducibility​

A build is reproducible when the same commit produces the same artefact.

  • Pin dependencies. Lock files are committed. Base images are referenced by digest, not tag.
  • Pin tool versions. The CI image, compiler and build tool versions are declared, not inherited from whatever the runner has today.
  • No build-time network surprises. Package registries are pinned or proxied; the build does not depend on an invisible upstream.
  • Build once, promote. The artefact tested in staging is the artefact deployed to production.
  • Record provenance. The build records the commit, the toolchain and the dependency manifest alongside the artefact.

Test layers​

LayerScopeRunsTarget
UnitA single function or classEvery commitFast; high coverage of logic
ComponentA service with its own dependencies mockedEvery commitFast; verifies service behaviour
ContractInteraction between consumer and providerEvery PRCatches interface drift
IntegrationService with real dependencies in a containerMerge to devCatches wiring and configuration errors
End-to-endThe deployed system through its interfaceMerge to stageCatches cross-service failure
PerformanceBehaviour under expected and peak loadBefore production releaseVerifies against SLO
SecuritySAST, DAST, dependency and secret scanningEvery commit; DAST before releaseBlocks high and critical findings

What to test​

Test behaviour, not implementation. A test that breaks when a function is renamed but not when the logic changes has negative value — it adds maintenance cost and provides no protection.

Prioritise:

  1. Business rules that are expensive to get wrong.
  2. Failure paths: timeouts, retries, partial failures, duplicate delivery.
  3. Boundaries: empty input, maximum size, unicode, time zones, currency rounding.
  4. Security-sensitive paths: authentication, authorisation, input validation.

Quality gates​

A gate blocks the pipeline. A warning does not, and a warning that is routinely ignored should be removed or promoted.

GateThresholdAction on failure
Unit test pass rate100%Block
Coverage on changed code≥ 80%Block
Coverage overall≥ 60%Warn
Static analysisNo new critical or high issuesBlock
Dependency vulnerabilitiesNo critical or high with a fix availableBlock
Secret scanZero findingsBlock
Container image scanNo critical findingsBlock
Licence complianceAllow-list onlyBlock
Integration tests100% passBlock
DAST (pre-release)No high or criticalBlock
Performancep95 within targetBlock

Server provisioning​

The build and test process also covers the infrastructure the tests run against:

  • Ephemeral environments created by Terraform for integration tests, destroyed after the run.
  • Preview environments per pull request where the customer's cost model supports it.
  • Self-hosted runners where the workload requires network adjacency or specific hardware, managed with the same patch discipline as production.

Teaching the process​

For each customer engagement we run a session covering:

  1. How to structure a build so it is reproducible.
  2. Which tests to write first, and how to make them fail meaningfully.
  3. How to set a coverage or quality threshold that is achievable and useful.
  4. How to read a failed pipeline and distinguish a flaky test from a real defect.
  5. How to change the pipeline without disabling the gates.