This skill should be used when the user asks about "Go test conventions", "ADR-008", "test naming", "table-driven tests", "go testing patterns", "testify", "how to write go tests", or needs guidance on Go testing methodology. Provides comprehensive guidance on high-quality Go testing following established conventions.
Provides comprehensive guidance on Go testing best practices, including ADR-008 naming conventions, table-driven tests, and assertion strategies. Claude will use this when users ask about Go test conventions, ADR-008, test naming patterns, or need help writing high-quality Go tests.
/plugin marketplace add dkoosis/cc-plugins/plugin install go-test-architect@cc-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill provides guidance on writing high-quality Go tests that catch regressions, document behavior, and enable safe refactoring.
Coverage is a discovery metric, not the goal. The real goals are:
10 tests that assert invariants > 100 tests that check magic strings.
All test functions must follow this format:
Test[Component]_[ExpectedBehaviour]_When_[StateUnderTest]
| Test Name | Component | Expected Behaviour | State Under Test |
|---|---|---|---|
TestValidator_RejectsInput_When_SchemaIsInvalid | Validator | RejectsInput | SchemaIsInvalid |
TestCache_ReturnsStaleValue_When_RefreshFails | Cache | ReturnsStaleValue | RefreshFails |
TestParser_ParsesEmptyInput_When_InputIsNil | Parser | ParsesEmptyInput | InputIsNil |
Avoid vague names:
TestFoo - unclear what's being testedTestSuccess - doesn't describe behaviorTestError - which error?package foo_test // External test package
import "your/module/foo"
func TestFoo_DoesX_When_Y(t *testing.T) {
// Tests only the public API
result := foo.Process(input)
}
Why: Tests survive refactoring. If internals change but behavior stays the same, tests still pass.
package foo // Same package
func TestInternalState_UpdatesCorrectly_When_Modified(t *testing.T) {
// Has access to unexported fields/functions
}
When: Only when testing unexported state is essential (e.g., verifying internal cleanup).
Always use table-driven tests with t.Run subtests:
func TestComponent_Behaviour_When_State(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input Input
want Output
wantErr error
inspect func(*testing.T, Output) // Optional invariant checks
}{
{
name: "error: nil input",
input: nil,
wantErr: ErrNilInput,
},
{
name: "success: valid input",
input: validInput,
want: expectedOutput,
inspect: func(t *testing.T, out Output) {
assert.True(t, out.Count >= 0, "count invariant")
},
},
}
for _, tc := range tests {
tc := tc // Capture for parallel
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := Process(tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, err, tc.wantErr)
return
}
require.NoError(t, err)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
if tc.inspect != nil {
tc.inspect(t, got)
}
})
}
}
require: Fails immediately. Use for setup/preconditions.assert: Continues after failure. Use for verifications.// Setup - use require (fail fast)
conn, err := db.Connect()
require.NoError(t, err)
// Verification - use assert (see all failures)
assert.Equal(t, expected, got)
assert.True(t, result.IsValid())
For complex struct comparisons, use github.com/google/go-cmp/cmp:
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
Tier 1 - Critical paths:
Tier 2 - Complex logic:
Tier 3 - Supporting utilities:
Look for these patterns in code:
| Anti-pattern | Problem | Fix |
|---|---|---|
time.Sleep in tests | Flaky, slow | Use channels or test clocks |
| Testing private fields | Breaks on refactor | Test through public API |
| Mocking third-party libs | Brittle | Wrap in interface you own |
| Only happy path | Misses bugs | Test error paths first |
err != nil check only | Doesn't verify error type | Use require.ErrorIs |
Use testdata/ directory for test fixtures:
package/
foo.go
foo_test.go
testdata/
valid_input.json
invalid_input.json
expected_output.golden
Access in tests:
data, err := os.ReadFile("testdata/valid_input.json")
# Run all tests with race detector
go test -race ./...
# Run with coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | sort -k3n
# Find uncovered packages
go tool cover -func=coverage.out | awk '$3 < 50.0 {print}'
Master authentication and authorization patterns including JWT, OAuth2, session management, and RBAC to build secure, scalable access control systems. Use when implementing auth systems, securing APIs, or debugging security issues.