| name | go-testing-code-review |
| description | Reviews Go test code for proper table-driven tests, assertions, and coverage patterns. Use when reviewing *_test.go files. |
Go Testing Code Review
This codebase primarily uses the standard testing package (not Ginkgo) for controller and CLI tests; keep the Ginkgo/envtest bullets for when they apply or for cross-repo consistency.
Quick Reference
Review Checklist
File Organization
Standard Go Testing
Ginkgo/Gomega (BDD Framework)
Kubernetes/Controller Testing
Critical Patterns
Table-Driven Tests
func TestAdd(t *testing.T) {
if Add(1, 2) != 3 {
t.Error("wrong")
}
if Add(0, 0) != 0 {
t.Error("wrong")
}
}
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive numbers", 1, 2, 3},
{"zeros", 0, 0, 0},
{"negative", -1, 1, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.want {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
Error Messages
if got != want {
t.Error("wrong result")
}
if got != want {
t.Errorf("GetUser(%d) = %v, want %v", id, got, want)
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("GetUser() mismatch (-want +got):\n%s", diff)
}
Parallel Tests
func TestFoo(t *testing.T) {
tests := []struct{...}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
})
}
}
Cleanup
func TestWithTempFile(t *testing.T) {
f, _ := os.CreateTemp("", "test")
defer os.Remove(f.Name())
}
func TestWithTempFile(t *testing.T) {
f, _ := os.CreateTemp("", "test")
t.Cleanup(func() {
os.Remove(f.Name())
})
}
Anti-Patterns
1. Testing Internal Implementation
func TestUser(t *testing.T) {
u := NewUser("alice")
if u.id != 1 {
t.Error("wrong id")
}
}
func TestUser(t *testing.T) {
u := NewUser("alice")
if u.ID() != 1 {
t.Error("wrong ID")
}
}
2. Shared Mutable State
var testDB = setupDB()
func TestA(t *testing.T) {
t.Parallel()
testDB.Insert(...)
}
func TestA(t *testing.T) {
db := setupTestDB(t)
t.Cleanup(func() { db.Close() })
db.Insert(...)
}
3. Assertions Without Context
assert.Equal(t, want, got)
assert.Equal(t, want, got, "user name after update")
When to Load References
- Reviewing test file structure → structure.md
- Reviewing mock implementations → mocking.md
Review Questions
- Are tests table-driven with named cases?
- Do error messages include input, got, and want?
- Are parallel tests isolated (no shared state)?
- Is cleanup done via t.Cleanup?
- Do tests verify behavior, not implementation?