All skills
cxuu avatar

/go-testing

@91f0c2e
by Charles Xucxuu/golang-skills165 stars
19

Use when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff. Also use when a user asks to write a test for a Go function, even if they don't mention specific patterns like table-driven tests or subtests. Does not cover benchmark performance testing (see go-performance).

Use this Skill: https://skilld.dev/gh/cxuu/golang-skills/go-testing

This session only. Nothing lands on disk.

referencesTEST-HELPERS.md

≈917 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Test Helpers, Assertions, and Comparisons

Detailed reference for writing test helpers, avoiding assertion libraries, and choosing between t.Error and t.Fatal. Sources: Google Go Style Guide, Uber Go Style Guide.


Test Helper Pattern

Test helpers must call t.Helper() first so failures point to the caller. Use t.Fatal for setup failures, and t.Cleanup for teardown.

func mustLoadTestData(t *testing.T, filename string) []byte {
    t.Helper()
    data, err := os.ReadFile(filename)
    if err != nil {
        t.Fatalf("Setup failed: could not read %s: %v", filename, err)
    }
    return data
}

func setupTestDB(t *testing.T) *sql.DB {
    t.Helper()
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        t.Fatalf("Could not open database: %v", err)
    }
    t.Cleanup(func() { db.Close() })
    return db
}

Key rules:

  • Call t.Helper() as the first statement to attribute failures to the caller
  • Use t.Fatal for setup failures (don't return errors from helpers)
  • Use t.Cleanup() for teardown instead of defer — it runs even if the test calls t.FailNow

Avoiding Assertion Libraries

Normative: Do not create or use assertion libraries.

Assertion libraries fragment the developer experience and often produce unhelpful failure messages.

// Bad:
assert.IsNotNil(t, "obj", obj)
assert.StringEq(t, "obj.Type", obj.Type, "blogPost")
assert.IntEq(t, "obj.Comments", obj.Comments, 2)

// Good: Use cmp package and standard comparisons
want := BlogPost{
    Type:     "blogPost",
    Comments: 2,
    Body:     "Hello, world!",
}
if diff := cmp.Diff(want, got); diff != "" {
    t.Errorf("GetPost() mismatch (-want +got):\n%s", diff)
}

Domain-Specific Comparisons

For domain-specific comparisons, return values or errors instead of calling t.Error:

func postLength(p BlogPost) int { return len(p.Body) }

func TestBlogPost(t *testing.T) {
    post := BlogPost{Body: "Hello"}
    if got, want := postLength(post), 5; got != want {
        t.Errorf("postLength(post) = %v, want %v", got, want)
    }
}

Comparisons and Diffs

Prefer cmp.Equal and cmp.Diff for complex types. Always include the direction key (-want +got) in diff messages.

// Struct comparison
want := &Doc{Type: "blogPost", Authors: []string{"isaac", "albert"}}
if diff := cmp.Diff(want, got); diff != "" {
    t.Errorf("AddPost() mismatch (-want +got):\n%s", diff)
}

// Protocol buffers
if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
    t.Errorf("Foo() mismatch (-want +got):\n%s", diff)
}

Avoid unstable comparisons — don't compare JSON/serialized output that may change. Compare semantically instead.


t.Error vs t.Fatal: Detailed Guidance

Use t.Error to keep tests going and report all failures in a single run:

// Good: Report all mismatches
if diff := cmp.Diff(wantMean, gotMean); diff != "" {
    t.Errorf("Mean mismatch (-want +got):\n%s", diff)
}
if diff := cmp.Diff(wantVariance, gotVariance); diff != "" {
    t.Errorf("Variance mismatch (-want +got):\n%s", diff)
}

Use t.Fatal when subsequent checks would be meaningless:

gotEncoded := Encode(input)
if gotEncoded != wantEncoded {
    t.Fatalf("Encode(%q) = %q, want %q", input, gotEncoded, wantEncoded)
}
gotDecoded, err := Decode(gotEncoded)
if err != nil {
    t.Fatalf("Decode(%q) error: %v", gotEncoded, err)
}

Don't Call t.Fatal from Goroutines

Normative: Never call t.Fatal, t.Fatalf, or t.FailNow from a goroutine other than the test goroutine. Use t.Error instead and let the goroutine return naturally.

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill is safe and follows Go testing best practices. It includes a well-sanitized script for generating test scaffolds, though it presents a minor surface for indirect prompt injection common to code-generation tools.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    8 files scanned · No issues

  • ZeroLeaks5mo

    1 finding · Score: 86/100

Signed by skilld at 91f0c2e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago
What it can do
Runs commands
All 1 allowed tools
Bash(bash:*)

README badge

README badge for cxuu/golang-skills/go-testing