Testing Charts: helm test and the ct Tool

Ship charts with confidence using in-cluster test hooks (helm test) and the chart-testing CLI (ct) for lint, install, and upgrade checks in CI.

Untested charts rot quietly. A value gets renamed, a template drifts, and you find out during a production upgrade. Two layers of testing keep that from happening.

Layer one: helm test (in-cluster smoke tests)

A chart can ship its own tests as Pods annotated with helm.sh/hook: test. After you install a release, helm test <release> runs those Pods against the live deployment — can the service actually be reached? does the DB connection open? A test that exits 0 passes; non-zero fails. This is the difference between "the manifests applied" and "the app actually works."

Layer two: ct (chart-testing in CI)

The ct CLI from the Helm project is built for pull-request pipelines. It detects which charts changed, enforces that version was bumped, runs ct lint against multiple value files, then ct install spins the chart up in a throwaway cluster (kind works great) and runs the helm test hooks. ct install --upgrade even installs the previous released version first and upgrades to your PR — catching the upgrade breakages that plain installs miss.

The rule that catches the most bugs: block any PR that changes a chart but forgets to bump version in Chart.yaml. ct enforces this for free.

Example

Example Β· yaml
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "{{ include "mychart.fullname" . }}-test"
  annotations:
    helm.sh/hook: test
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
  restartPolicy: Never
  containers:
    - name: wget
      image: busybox:1.36
      command: ['wget']
      args:
        - '--spider'                     # HEAD request, exit non-zero on failure
        - '{{ include "mychart.fullname" . }}:{{ .Values.service.port }}'
---
# Run it after install:  helm test my-web
# In CI:  ct lint --charts ./mychart && ct install --charts ./mychart --upgrade

When to use it

  • A chart maintainer runs helm test after every staging install in CI to confirm the deployed service responds to health checks before marking the pipeline green.
  • A platform team uses the chart-testing (ct) CLI to lint and install all charts in their monorepo on every PR, only testing charts whose files changed.
  • A developer adds a connection-test Pod as a Helm test hook so any user who installs the chart can run helm test to quickly verify their deployment is functioning.

More examples

Run built-in chart tests

Installs or upgrades a release, waits for readiness, then runs all test hook Pods and prints their logs to verify the deployment.

Example Β· bash
helm upgrade --install my-app ./myapp \
  -f values-staging.yaml \
  --wait -n staging

helm test my-app -n staging --logs

Install chart-testing tool

Installs the ct CLI and runs lint against charts that changed versus the main branch, avoiding unnecessary testing of unchanged charts.

Example Β· bash
# Install ct (chart-testing)
pip3 install yamllint
curl -fsSL https://github.com/helm/chart-testing/releases/download/v3.10.1/chart-testing_3.10.1_linux_amd64.tar.gz | tar xz
mv ct /usr/local/bin/

# Lint all changed charts
ct lint --target-branch main

ct install in CI

Uses ct install to install only the changed charts into a temporary namespace, running their tests and cleaning up after.

Example Β· bash
# .github/workflows/ci.yaml snippet (run in bash)
ct install \
  --target-branch main \
  --chart-dirs charts/ \
  --namespace ct-testing \
  --create-namespace

Discussion

  • Be the first to comment on this lesson.
Testing Charts: helm test and the ct Tool β€” Helm | SoundsCode