Agent skill

NIC Testing Patterns

by nginx in nginx/kubernetes-ingress

Testing conventions for the NGINX Ingress Controller repo: Go table-driven tests, mandatory snapshot regeneration, Helm tests and Python pytest integration tests.

Apache-2.0Auto-check passedTesting & QA

Install NIC Testing Patterns

skills CLI
$ npx skills add nginx/kubernetes-ingress --skill nic-testing -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install nginx/kubernetes-ingress nic-testing --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/nginx/kubernetes-ingress.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/nic-testing .claude/skills/nic-testing && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
nic-testing
GitHub stars
5.1k
Token cost
~2.8k tokens
SKILL.md length
1,061 words
Files
1
Skills in repo
9
Repo updated
First seen
Licence
Apache-2.0

At a glance

Testing conventions for the NGINX Ingress Controller repo: Go table-driven tests, mandatory snapshot regeneration, Helm tests and Python pytest integration tests.

  • Works in 6 steps: Add or extend a test case first.… → Run make test-update-snaps. → Inspect what actually changed → …
  • Writing Go unit or table-driven tests for the NGINX Ingress Controller
  • SKILL.md covers Build and Test Commands, Snapshot Tests -- MANDATORY…, Go Unit Tests and Helm Tests, plus 3 more sections
  • Calls make, git and go

What it does

NIC's tests are driven through make targets, and the skill says to prefer them over raw go test. make test runs all Go tests with the aws and helmunit tags and shuffling, make test-update-snaps regenerates golden files, and the table also lists make lint, make format, make cover and make lint-python for isort and black. Helm tests compile only with the helmunit build tag, which make test already includes.

Snapshot tests are called a hard gate. Three packages hold golden files: version1 for Ingress templates, version2 for VirtualServer, VirtualServerRoute and TransportServer templates, and charts/tests for rendered Helm manifests. A trigger table says what to do when a template, a template struct field, config generation or a Helm chart file changes. The required order is to add or extend a test case first, then run make test-update-snaps, then inspect what actually changed.

When your agent uses it

  • Writing Go unit or table-driven tests for the NGINX Ingress Controller
  • Changing an nginx template and updating its snapshot golden files
  • Adding Helm chart tests for new chart values
  • Writing pytest integration tests for the Ingress Controller
  • Checking which make target runs tests, linting or coverage

Example prompts

  • “I added a new directive to nginx.tmpl, so update the snapshot tests the right way.”
  • “Write table-driven tests for the new policy handler in internal/configs.”
  • “Add a Helm test case for the new value in values.yaml and regenerate the snapshots.”

Requirements

  • Go toolchain and make
  • Docker, for make lint
  • Python with pytest, for the integration tests

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Add or extend a test case first. Regenerating alone only re-records existing fixtures. If no fixture sets your new field, the golden file…
  2. Run make test-update-snaps.
  3. Inspect what actually changed
  4. Read the diff and confirm your directive is present in the golden output for every edition that supports it. An empty diff after a .tmpl…
  5. Run make test to confirm the suite is green against the regenerated files.
  6. Commit the snapshots changes in the same commit as the template change.

What it can do on your machine

Read from SKILL.md and the folder at commit f6d0615. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • make
    • git
    • go

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

NIC Testing Patterns loads about 2.8k tokens when it runs. Until then it costs about 65 tokens; SKILL.md has 1,061 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~65
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from nginx/kubernetes-ingress at commit f6d0615, republished under its Apache-2.0 licence (© nginx). 1,061 words, ~2,802 tokens.

Download SKILL.mdSave it as .claude/skills/nic-testing/SKILL.md (or your agent's skills folder).
name
nic-testing
description
Testing patterns for NIC including Go table-driven tests, snapshot tests, and Python integration tests. Use when writing unit tests, snapshot tests, policy tests, template tests, Helm tests, or pytest integration tests for the Ingress Controller.

NIC Testing Patterns

Build and Test Commands

CommandPurpose
make testRun all Go tests (-tags=aws,helmunit -shuffle=on ./...)
make test-update-snapsRegenerate snapshot golden files (UPDATE_SNAPS=always)
make lintgolangci-lint via Docker, diff against origin/main
make formatgoimports + gofumpt
make coverGenerate test coverage report
make lint-pythonPython test formatting: isort + black

Always use make test over raw go test. Run make test-update-snaps when template output changes.

Note: Helm tests use the //go:build helmunit build tag -- they are only compiled and run when -tags=helmunit is passed (included in make test).


Snapshot Tests -- MANDATORY workflow

This is the single most frequently missed step. Treat it as a hard gate, not an optional cleanup.

The three snapshot packages
PackageGolden filesCovers
internal/configs/version1internal/configs/version1/__snapshots__/Ingress templates (nginx.tmpl, nginx.ingress.tmpl, and Plus variants)
internal/configs/version2internal/configs/version2/__snapshots__/VirtualServer / VSR / TransportServer templates (OSS + Plus)
charts/testscharts/tests/__snapshots__/Rendered Helm manifests (terratest, helmunit build tag)
Trigger table -- if you touched this, snapshots are in scope
ChangeSnapshot action required
Any *.tmpl fileRegenerate and add a case that exercises the new directive
Template struct field (version1/config.go, version2/http.go, version2/stream.go)Add the field to the fixture used by the snapshot test, then regenerate
Config generation (internal/configs/*.go) that changes rendered outputRegenerate; confirm the diff matches the intended output
charts/nginx-ingress/templates/**, values.yaml, _helpers.tplAdd charts/tests/testdata/<feature>.yaml + a helmunit_test.go case, then regenerate
Deleting or renaming a snapshot testRegenerate -- snaps.Clean prunes the obsolete entry from the golden file
Required sequence
  1. Add or extend a test case first. Regenerating alone only re-records existing fixtures. If no fixture sets your new field, the golden file will never contain your directive and the feature ships untested.

  2. Run make test-update-snaps.

  3. Inspect what actually changed:

    bash
    git status --short internal/configs/version1/__snapshots__ \
      internal/configs/version2/__snapshots__ charts/tests/__snapshots__
    git diff -- '**/__snapshots__/**'
  4. Read the diff and confirm your directive is present in the golden output for every edition that supports it. An empty diff after a .tmpl change means no fixture exercises the new branch -- go back to step 1.

  5. Run make test to confirm the suite is green against the regenerated files.

  6. Commit the __snapshots__ changes in the same commit as the template change.

Edition parity -- OSS vs Plus

OSS and Plus templates are separate files with separate golden entries, so decide up front which editions the feature targets:

FeatureExpected snapshot diff
Supported by both editionsBoth the OSS and Plus golden files change
Plus-only (health checks, OIDC, WAF, zone_sync, NGINX Plus API)Only the Plus golden file changes -- the directive must never appear in OSS output
OSS-onlyOnly the OSS golden file changes

A one-sided diff is a bug only when the feature is supposed to be shared. Never add a Plus-only directive to an OSS snapshot to "fix" a one-sided diff -- that means the directive leaked into the OSS template and NGINX OSS will fail to start.

Self-check before declaring done
  • Every .tmpl I edited has at least one snapshot case that renders the new directive.
  • The golden files changed for exactly the editions the feature supports -- both for shared features, Plus-only for Plus features.
  • No Plus-only directive appears in an OSS golden file.
  • git diff on __snapshots__ is non-empty and reviewed line by line.
  • make test passes without UPDATE_SNAPS.
  • The regenerated golden files are staged for commit.

Go Unit Tests

Table-Driven Tests (primary pattern)
go
func TestValidateMyPolicy(t *testing.T) {
    t.Parallel()
    tests := []struct {
        policy *v1.Policy
        isPlus bool
        msg    string
    }{
        { /* valid case */ },
        { /* edge case */ },
    }
    for _, test := range tests {
        err := ValidatePolicy(test.policy, test.isPlus, false, false)
        if err != nil {
            t.Errorf("ValidatePolicy returned error %v for case: %s", err, test.msg)
        }
    }
}
Naming Convention

Two conventions are in use -- both are acceptable:

Policy/transport tests (policy_test.go, transportserver_test.go):

  • TestValidate<Thing>_PassesOnValidInput
  • TestValidate<Thing>_FailsOnInvalidInput

VirtualServer/general tests (virtualserver_test.go and most other files):

  • TestValidate<Thing> (valid input, often with subtests)
  • TestValidate<Thing>Fails (invalid input)
  • TestGenerate<Feature>
Snapshot Test Mechanics

Every package that uses snaps.MatchSnapshot needs exactly one TestMain that prunes stale snapshots. It lives in a single file per package (version1/template_test.go, version2/templates_test.go, charts/tests/helmunit_test.go) -- do not add a second one when you create a new test file in an existing package:

go
func TestMain(m *testing.M) {
    snaps.Clean(m, snaps.CleanOpts{Sort: true})
}

Example snapshot test:

go
func TestVirtualServerForNginx(t *testing.T) {
    t.Parallel()
    executor := newTmplExecutorNGINX(t)
    data, err := executor.ExecuteVirtualServerTemplate(&virtualServerCfg)
    require.NoError(t, err)
    snaps.MatchSnapshot(t, string(data))
}
Helper Conventions
  • Always call t.Parallel() at the start
  • Use t.Helper() in helper functions
  • Use github.com/google/go-cmp/cmp for deep struct comparison
  • Use github.com/gkampitakis/go-snaps/snaps for snapshot tests

Show full SKILL.md (422 more words)Show less

Helm Tests

Location: charts/tests/

  • helmunit_test.go -- Helm snapshot tests using terratest + go-snaps
  • testdata/ -- values.yaml overrides per test scenario

Add a test values file in charts/tests/testdata/<feature>.yaml and a corresponding test case in helmunit_test.go.


Python Integration Tests

Location: tests/suite/

Markers must be registered

pytest runs with --strict-markers (pyproject.toml, [tool.pytest.ini_options] addopts). Any new @pytest.mark.<name> must be added to the markers list in pyproject.toml at the repository root or the whole suite errors out. If the marker should run in CI, also add it to the relevant smoke matrix in .github/data/matrix-smoke-*.json.

Test Class Pattern
python
@pytest.mark.policies
@pytest.mark.policies_myfeature
@pytest.mark.parametrize(
    "crd_ingress_controller, virtual_server_setup",
    [({"type": "complete", "extra_args": [...]},
      {"example": "virtual-server", "app_type": "simple"})],
    indirect=True,
)
class TestMyFeaturePolicies:
    def test_basic_functionality(self, kube_apis, crd_ingress_controller,
                                  virtual_server_setup, test_namespace):
        # 1. Create policy from YAML
        pol_name = create_policy_from_yaml(
            kube_apis.custom_objects, yaml_src, test_namespace
        )
        wait_before_test()
        # 2. Patch VS to reference policy
        patch_virtual_server_from_yaml(...)
        # 3. Assert HTTP responses
        resp = requests.get(url, headers={"host": vs_host})
        assert resp.status_code == 200
        assert "Expected-Header" in resp.headers
        # 4. Cleanup
        delete_policy(kube_apis.custom_objects, pol_name, test_namespace)
        patch_virtual_server_from_yaml(...)  # restore original
Fixtures and Utilities
  • Common fixtures: kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace
  • Fixtures: tests/suite/fixtures/ (setup/teardown lifecycle)
  • Utilities: tests/suite/utils/ (create_policy_from_yaml, patch_virtual_server_from_yaml, delete_policy, wait_before_test)
  • Prefer event/status-based waits over fixed sleeps when possible
File Naming
  • test_<feature>_policies_vs.py -- VirtualServer policy tests
  • test_<feature>_policies_vsr.py -- VirtualServerRoute policy tests
  • test_<feature>_policies_ingress.py -- Ingress policy tests
Test Data

Store YAML manifests in tests/data/<feature>/.


Generated Artifacts Verified by CI

The verify-codegen job in ci.yml re-runs each generator and diffs a specific path. Run the matching target and commit the result:

You changedRunPath CI diffs
pkg/apis/**/types.gomake update-codegenpkg/**
pkg/apis/** kubebuilder markersmake update-crdsconfig/crd/bases only
Telemetry Data / NICResourceCounts in internal/telemetry/exporter.gomake telemetry-schemainternal/telemetry
Any import / dependencygo mod tidygo.mod, go.sum
Any .tmpl or template structmake test-update-snapsnot checked by verify-codegen -- fails in unit-tests instead

The checks are path-scoped, not repository-wide. make update-crds also rewrites deploy/crds*.yaml and docs/crd/, but CI never diffs those paths -- forgetting to commit them produces a green build and stale published CRD bundles. Verify them yourself with git status after regenerating.

charts/nginx-ingress/crds is a symlink to config/crd/bases/ -- never edit it directly.


Gotchas

  • Always run make test-update-snaps after changing any .tmpl file -- snapshot tests will fail otherwise
  • Regenerating is not the same as testing. If no fixture sets your new field, the golden file will not change and the feature has zero coverage. Add the test case first
  • Never run raw go test -- use make test which includes required build tags (aws, helmunit)
  • Snapshot golden files are in __snapshots__/ directories -- commit the regenerated files with the change that caused them
  • TestMain with snaps.Clean(m, snaps.CleanOpts{Sort: true}) is per package, not per file -- adding a second one to the same package breaks the build
  • OSS and Plus templates are separate files, so they have separate snapshot entries -- a one-sided diff means you forgot the sibling template, unless the feature is Plus-only, in which case only the Plus golden file must change
  • New pytest markers must be registered in pyproject.toml -- --strict-markers is enabled
  • Python tests use indirect=True parametrize for IC + VS setup -- do not remove this

© nginx, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .github/skills/nic-testing of nginx/kubernetes-ingress.

Open the folder on GitHubat commit f6d0615

Compare with similar skills

NIC Testing Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

NIC Testing Patterns compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
NIC Testing Patterns this skillnginx/kubernetes-ingress5.1k—~2.8kAutomated safety check: PassApache-2.0
Issue WriterNVIDIA/container-canary309—~1.1kAutomated safety check: PassApache-2.0
Backend Testingbiersoeckli/QuickStack361—~670Automated safety check: PassGPL-3.0
Discover Testingrand/cc-polymath181—~513Automated safety check: PassMIT
Chart Testsastronomer/astronomer491—~3.2kAutomated safety check: PassCustom licence
Benchflow Experiment Reviewbenchflow-ai/benchflow353—~4kAutomated safety check: PassApache-2.0

Similar skills

  • Issue Writer

    NVIDIA/container-canary

    Official

    Draft and revise concise, human-focused GitHub issues for pytest-kind-ng.

    309 GitHub stars~1.1k tokensUpdated 1 mo ago
    Testing & QAAuto-check passed
  • Backend Testing

    biersoeckli/QuickStack

    Create and review QuickStack backend unit and integration tests using the project's Vitest, Prisma, SQLite, and k3s conventions.

    361 GitHub stars~670 tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Discover Testing

    rand/cc-polymath

    Automatically discover testing skills when working with unit testing, integration testing, e2e testing, TDD, test coverage, mocking, pytest, Jest, or test automation.

    181 GitHub stars~513 tokensUpdated 7 mo ago
    Testing & QAAuto-check passed
  • Chart Tests

    astronomer/astronomer

    A skill your agent uses when writing, editing, reviewing, or running Helm chart tests for the Astronomer APC repository.

    491 GitHub stars~3.2k tokensUpdated today
    DevOps & CloudAuto-check passed
  • Benchflow Experiment Review

    benchflow-ai/benchflow

    Review Benchflow or SkillsBench task-run trajectories and integration-test Benchflow code changes.

    353 GitHub stars~4k tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Code Patterns

    Aedelon/claude-code-blueprint

    Reference patterns for REST APIs, pytest/vitest testing, Docker multi-stage builds, GitHub Actions CI/CD, PostgreSQL, TypeScript generics, Python async, and React Server Components.

    120 GitHub stars~1.2k tokensUpdated 7 mo ago
    DevOps & CloudAuto-check passed

More from nginx/kubernetes-ingress

All 9 skills in this repo
  • Gives step-by-step checklists for adding Ingress annotations, VirtualServer fields and Helm values to the NGINX Kubernetes Ingress Controller, with common gotchas.

    5.1k GitHub stars~1.4k tokensUpdated today
    Auto-check passed
  • NGINX Ingress Policy CRD Guide

    nginx/kubernetes-ingress

    Step-by-step checklist for adding a new Policy CRD type to the NGINX Ingress Controller, from the Go types and validation to config generation and templates.

    5.1k GitHub stars~2k tokensUpdated today
    Auto-check passed
  • NGINX Ingress CI Pipelines

    nginx/kubernetes-ingress

    Explains how the NGINX Ingress Controller's GitHub Actions workflows, reusable workflows, build matrices and release pipeline fit together across two repositories.

    5.1k GitHub stars~5k tokensUpdated today
    Auto-check passed
  • Explains the multi-stage Dockerfile, the 25 image variant combinations, and the Makefile targets for building NGINX Ingress Controller images.

    5.1k GitHub stars~2.9k tokensUpdated today
    Auto-check passed
  • NGINX Ingress Controller Structure

    nginx/kubernetes-ingress

    Maps the NGINX Kubernetes Ingress Controller codebase: repository layout, architectural layers, layer-crossing rules and which files are generated.

    5.1k GitHub stars~3.8k tokensUpdated today
    Auto-check passed
  • NGINX Ingress Controller Debugging

    nginx/kubernetes-ingress

    Troubleshooting patterns for the NGINX Ingress Controller: reload failures, custom resources that have no effect, controller panics and snapshot test failures.

    5.1k GitHub stars~1.7k tokensUpdated today
    Auto-check passed

Questions about NIC Testing Patterns

What does NIC Testing Patterns do?

Testing conventions for the NGINX Ingress Controller repo: Go table-driven tests, mandatory snapshot regeneration, Helm tests and Python pytest integration tests. NIC's tests are driven through make targets, and the skill says to prefer them over raw go test. make test runs all Go tests with the aws and helmunit tags and shuffling, make test-update-snaps regenerates golden files, and the table also lists make lint, make format, make cover and make lint-python for isort and black.

When should I use NIC Testing Patterns?

NIC Testing Patterns fits situations like: writing Go unit or table-driven tests for the NGINX Ingress Controller; changing an nginx template and updating its snapshot golden files; adding Helm chart tests for new chart values; writing pytest integration tests for the Ingress Controller.

How do I install NIC Testing Patterns in Claude Code?

Run `npx skills add nginx/kubernetes-ingress --skill nic-testing -a claude-code`. Or copy the skill folder (.github/skills/nic-testing in nginx/kubernetes-ingress) into .claude/skills/nic-testing in your project. Claude Code loads it when a task matches its description.

How do I install NIC Testing Patterns in Codex?

Run `npx skills add nginx/kubernetes-ingress --skill nic-testing -a codex`. Or copy the skill folder (.github/skills/nic-testing in nginx/kubernetes-ingress) into .agents/skills/nic-testing in your project. Codex loads it when a task matches its description.

Can I use NIC Testing Patterns in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add nginx/kubernetes-ingress --skill nic-testing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/nic-testing, .gemini/skills/nic-testing, .github/skills/nic-testing and .opencode/skills/nic-testing in your project.

What does NIC Testing Patterns need to run?

Going by SKILL.md and its folder, NIC Testing Patterns needs the command-line tools its instructions call (make, git and go). Our summary lists: Go toolchain and make; Docker, for make lint; Python with pytest, for the integration tests.

Does NIC Testing Patterns access the network?

SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is NIC Testing Patterns safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does NIC Testing Patterns use?

NIC Testing Patterns is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does NIC Testing Patterns use?

About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to NIC Testing Patterns?

Skills that share tags, products or a category with NIC Testing Patterns: Issue Writer (NVIDIA/container-canary, 309 stars), Backend Testing (biersoeckli/QuickStack, 361 stars), Discover Testing (rand/cc-polymath, 181 stars) and Chart Tests (astronomer/astronomer, 491 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains NIC Testing Patterns?

nginx (a GitHub organization) maintains it in nginx/kubernetes-ingress, which has 5,082 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 7, 2026.

Source: nginx/kubernetes-ingress on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.