Expertise hub / Process
Process DevOps 4 min read

A CI/CD pipeline without tests is a motorway without guardrails.

You go fast. Until you don't. Many teams optimise their pipeline for speed and forget that the pipeline itself is the quality contract.

That contract only works if the right checks are in place. Anything that isn’t checked can slip through. And anything that fails without blocking a release is not a quality gate, it’s just decoration.

What belongs in a good pipeline?

1. Linting and static analysis

Cheap, fast, and catches the simple mistakes before they show up anywhere else.

2. Unit tests

Always, on every commit. This is the base layer that should never be missing.

3. Integration tests

On every push to a feature branch, so you quickly know whether components still work together.

4. End-to-end smoke tests

On merge to main, as a final check on the most important user flows.

Speed versus completeness

Not everything needs to run on every commit. Unit tests always, heavy end-to-end tests on merge to main, performance and security every night or every week. Make deliberate choices about what runs when.

A pipeline that takes 45 minutes gets bypassed. Speed is quality too.

That last point is often underrated. A pipeline that takes too long invites workarounds: pushing straight to production, skipping tests "just this once", or simply ignoring the pipeline because it's always red anyway. So the pipeline needs to be thorough, but also fast enough to actually be followed.

Failing tests block the deploy, always

Tests without enforcement are decoration

If a failing test has no consequences, it also has no value. Tie your tests to the deployment process, because making quality enforceable is the only way to actually guarantee it.

Concretely, that means: the deploy step has a needs dependency on the test step, and nothing more than that.

.github/workflows/ci.ymlGitHub Actions
// deploy only starts once both test steps pass
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint
      - run: npm run test:unit
      - run: npm run test:integration

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: success()
    steps:
      - run: npm run deploy

No needs: test? Then your tests still run, but the deploy doesn't wait for them. That one keyword is the difference between a quality contract and a report nobody reads.

The pipeline is your quality contract, on every change, no exceptions. A good pipeline isn't a technical work of art. It's an automated quality contract that does exactly what it promises: let nothing through that hasn't been checked.

Carousel: tests in your CI/CD pipeline
// Also as a carousel

This article first appeared as a carousel on LinkedIn.

View on LinkedIn
// Let's talk

Sounds familiar?

We'll review your test approach and tell you honestly where the gains are. And where they aren't.

Book a call
// Read next