Rule

go-testing

1 ↓ | .tar.gz

Go testing conventions applied to all _test.go files. Standard library only, table-driven, behavior-focused.

Write tests that are focused, readable, and use only the standard library.

Framework

  • Standard library only — no testify or external test frameworks.
  • Run tests: go test ./...
  • Run with race detection: go test -race ./...

Structure

  • Test files live next to source: handlers.gohandlers_test.go
  • Test fixtures go in testdata/ directories.
  • HTTP handlers tested with net/http/httptest.

Table-Driven Tests

  • Use table-driven tests with named subtests:

    tests := []struct {
        name string
        input string
        want  string
    }{
        {"empty input", "", ""},
        {"single word", "hello", "HELLO"},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Func(tt.input)
            if got != tt.want {
                t.Errorf("Func(%q) = %q, want %q", tt.input, got, tt.want)
            }
        })
    }
    

Failure Messages

  • Include function name, inputs, got, and want: t.Errorf("Func(%v) = %v, want %v", input, got, want)
  • Never use generic messages like "unexpected result".

Error Assertions

  • Use errors.Is() and errors.As() — never string comparison on error messages.

Test Helpers

  • Test helpers must call t.Helper() as the first statement so failures point to the caller.

Scope

  • Test behavior, not implementation details.
  • Omit tests for trivial logic (simple getters, constant returns). Prioritize business logic and conditional branches.

Coverage

  • Do not aim for 100% coverage. Cover decisions and branches that matter.
└── RULE.md
RULE.md | | Raw

Go Testing

Write tests that are focused, readable, and use only the standard library.

Framework

  • Standard library only — no testify or external test frameworks.
  • Run tests: go test ./...
  • Run with race detection: go test -race ./...

Structure

  • Test files live next to source: handlers.gohandlers_test.go
  • Test fixtures go in testdata/ directories.
  • HTTP handlers tested with net/http/httptest.

Table-Driven Tests

  • Use table-driven tests with named subtests:

    tests := []struct {
        name string
        input string
        want  string
    }{
        {"empty input", "", ""},
        {"single word", "hello", "HELLO"},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Func(tt.input)
            if got != tt.want {
                t.Errorf("Func(%q) = %q, want %q", tt.input, got, tt.want)
            }
        })
    }
    

Failure Messages

  • Include function name, inputs, got, and want: t.Errorf("Func(%v) = %v, want %v", input, got, want)
  • Never use generic messages like "unexpected result".

Error Assertions

  • Use errors.Is() and errors.As() — never string comparison on error messages.

Test Helpers

  • Test helpers must call t.Helper() as the first statement so failures point to the caller.

Scope

  • Test behavior, not implementation details.
  • Omit tests for trivial logic (simple getters, constant returns). Prioritize business logic and conditional branches.

Coverage

  • Do not aim for 100% coverage. Cover decisions and branches that matter.

[1.0.0] - 2026-06-23

Added