Help us improve
Share bugs, ideas, or general feedback.
From gopilot
Guides TDD baby steps in Go: red-green-refactor cycles, table-driven tests with testify, t.Run subtests, t.Helper. Use for writing tests, tight feedback loops, and breaking features into small steps.
npx claudepluginhub gonzaloserrano/gopilot --plugin gopilotHow this skill is triggered — by the user, by Claude, or both
Slash command
/gopilot:go-tdd-baby-stepsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Test-Driven Development using the smallest possible increments, with Go idioms.
Guides test-driven development with Red-Green-Refactor cycle, including patterns for Jest, Vitest, pytest, and Go testing.
Guides using Bun as JavaScript runtime, package manager, bundler, and test runner. Covers choosing Bun vs Node, Node migration, and Vercel deployment support.
Share bugs, ideas, or general feedback.
Test-Driven Development using the smallest possible increments, with Go idioms.
These laws create a tight feedback loop: write a tiny test, watch it fail, write just enough code to pass.
Each cycle should take ~2 minutes. If longer, the step is too big.
If stuck or code is getting messy:
Never debug longer than the cycle itself. Revert instead.
Build up the test table incrementally — each row adds ONE behavior.
func TestParseAmount(t *testing.T) {
tests := []struct {
name string
input string
want int
wantErr bool
}{
{name: "empty string", input: "", want: 0, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseAmount(tt.input)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
Production code (fake it):
func ParseAmount(s string) (int, error) {
return 0, errors.New("empty")
}
Add one row, generalize production code:
{name: "single digit", input: "5", want: 5},
func ParseAmount(s string) (int, error) {
if s == "" {
return 0, errors.New("empty input")
}
return strconv.Atoi(s)
}
{name: "negative number", input: "-3", want: -3},
{name: "leading zeros", input: "007", want: 7},
{name: "non-numeric", input: "abc", wantErr: true},
Each row forces at most one production code change.
Use t.Run for progression and t.Helper for shared assertions:
func assertStack(t *testing.T, s *Stack, wantLen int, wantEmpty bool) {
t.Helper()
assert.Equal(t, wantLen, s.Len())
assert.Equal(t, wantEmpty, s.IsEmpty())
}
func TestStack(t *testing.T) {
t.Run("new stack is empty", func(t *testing.T) {
s := NewStack()
assertStack(t, s, 0, true)
})
t.Run("push one element", func(t *testing.T) {
s := NewStack()
s.Push(42)
assertStack(t, s, 1, false)
})
t.Run("pop returns last pushed", func(t *testing.T) {
s := NewStack()
s.Push(42)
got, err := s.Pop()
require.NoError(t, err)
assert.Equal(t, 42, got)
assertStack(t, s, 0, true)
})
t.Run("pop empty stack returns error", func(t *testing.T) {
s := NewStack()
_, err := s.Pop()
require.Error(t, err)
})
}
Each t.Run block is a baby step — one new behavior per subtest.
Prefer simpler transformations:
if)Choose the transformation that requires the least code change.