Course contentsShow
← Docker, Kubernetes & CI/CD
Lesson 131 of 8022. Docker Image LifecycleFree lesson

Testing Artifacts Within Intermediate Stages

You will add a verification stage to your pipeline that runs unit tests against compiled code before finalizing the production image.

In this lesson, you will learn how to shift your quality assurance left by executing unit tests directly inside your Docker build process before the final image is ever created.

The Problem with Post-Build Testing

In many pipelines, developers compile code, package it into an image, and only then run tests against the resulting container. This is inefficient: if the tests fail, you’ve already spent time building a heavy production image that you now have to discard. By testing within an intermediate stage of your Dockerfile, you ensure that the code is verified while it is still in its "builder" state.

Integrating Tests into the Multi-Stage Build

We can use a dedicated build stage to perform verification. If the test command fails, the Docker build process stops immediately. This prevents the downstream "production" stage from even starting if the code quality is subpar.

Here is how you can implement this in your Dockerfile:

# Stage 1: Build and Test
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# Run unit tests; if this fails, the build stops here!
RUN npm test

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
# Only copy the artifacts if the tests passed in the previous stage
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]

In this example, the RUN npm test command acts as a gatekeeper. Because the instruction follows the COPY of your source code but precedes the creation of the final FROM stage, Docker guarantees that no production-ready image will be produced from broken code.

Why This Matters

By testing in an intermediate stage, you treat your Dockerfile as a formal part of your CI/CD pipeline. You aren't just copying files; you are enforcing a "build-and-verify" contract. This keeps your production images lean, prevents the distribution of buggy code, and provides faster feedback loops because you catch errors during the build phase rather than the deployment phase.

Key Takeaway: Embedding your test suite as a RUN instruction within an intermediate build stage ensures that only verified, stable code is ever packaged into your final production image.