What are the rules and pitfalls of t.Parallel()?
Question 380MediumGo 1.22 to 1.25
- Parallel tests in a package run concurrently up to
-parallel(defaultGOMAXPROCS). Packages themselves run in parallel as separate processes (-p). - Top-level parallel tests start only after all sequential top-level tests finish.
t.Setenvandt.Chdir(1.24) panic if the test or an ancestor calledt.Parallel, because env vars and cwd are process-global.- Shared mutable state (package vars, global registries like
http.DefaultServeMux,time.Nowoverrides, a single DB schema) causes flaky failures — give each test its own instance. t.Fatalmust be called from the test goroutine, not from goroutines the test spawns; uset.Erroror send errors back on a channel.
func TestUsers(t *testing.T) {
t.Parallel()
db := newTestDB(t) // registers t.Cleanup(db.Close); unique schema per test
for _, tc := range userCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
ctx := t.Context() // Go 1.24: canceled just before Cleanup runs
if err := db.CreateUser(ctx, tc.user); (err != nil) != tc.wantErr {
t.Fatalf("CreateUser(%v) err = %v", tc.user, err)
}
})
}
}
Always combine parallel tests with go test -race; parallelism is how data races in test helpers and production code get exposed.
More on Performance, Profiling & Testing
- Q378Write an idiomatic table-driven test with subtests. Why is this the preferred Go style?
- Q379What does this test print, and in what order?
- Q381Compare t.Cleanup, defer, and TestMain for setup/teardown. When is each appropriate?
- Q382How does native fuzzing work in Go? Write a fuzz test and explain the corpus.
- Q383What is testing/synctest and what problem does it solve?
- Q384How do you mock dependencies in Go without a mocking framework? Where should the interface live?