Testing Concurrent Go with synctest

Notes from Alexander Baygeldin’s GopherCon 2026 talk, “(Sync)testing Concurrent Code with Confidence.” Testing concurrent code used to mean picking one of three bad options: hacky (poke at internals), flaky (time.Sleep(100 * time.Millisecond) and hope), or slow (sleep long enough that it’s reliable). testing/synctest removes the tradeoff by giving the test a fake clock. The fake clock Inside synctest.Test, time doesn’t pass on its own. It jumps forward only when every goroutine in the bubble is blocked. A one-hour timeout resolves instantly and deterministically. ...

August 16, 2026 · 2 min · Moises Vega

Table-Driven Tests in Go

Every Go codebase converges on the same test shape: a slice of cases, a loop, one t.Run per case. It is the closest thing Go has to a testing idiom, and it is worth writing deliberately rather than by habit. The shape func TestParseDuration(t *testing.T) { tests := []struct { name string give string want time.Duration wantErr string }{ { name: "seconds", give: "30s", want: 30 * time.Second, }, { name: "compound", give: "1h30m", want: 90 * time.Minute, }, { name: "missing unit", give: "30", wantErr: "missing unit", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseDuration(tt.give) if tt.wantErr != "" { require.ErrorContains(t, err, tt.wantErr) return } require.NoError(t, err) assert.Equal(t, tt.want, got) }) } } Three things earn their place here. ...

August 12, 2026 · 3 min · Moises Vega