Use t.Parallel() to mark a test function as runnable concurrently with other parallel tests, allowing them to execute simultaneously on available CPU cores rather than sequentially. You must call it as the very first statement in your test function, and it only works if the test runner is invoked with the -parallel flag (which is the default behavior for go test).
Here is a practical example showing how to structure a test file with parallel execution and a shared resource that requires synchronization:
package main
import (
"fmt"
"sync"
"testing"
"time"
)
// A shared resource that needs protection during parallel execution
var counter int
var mu sync.Mutex
func TestIncrementParallel(t *testing.T) {
// Must be the first call in the test function
t.Parallel()
mu.Lock()
counter++
current := counter
mu.Unlock()
// Simulate some work
time.Sleep(100 * time.Millisecond)
fmt.Printf("Test %s: counter is %d\n", t.Name(), current)
}
func TestIncrementParallel2(t *testing.T) {
t.Parallel()
mu.Lock()
counter++
current := counter
mu.Unlock()
time.Sleep(100 * time.Millisecond)
fmt.Printf("Test %s: counter is %d\n", t.Name(), current)
}
func TestSequentialOnly(t *testing.T) {
// This test runs sequentially, waiting for all parallel tests to finish
// before it starts, unless explicitly grouped differently.
t.Log("Running sequentially after parallel tests complete")
}
Run the tests with the standard command:
go test -v -parallel 4
The -parallel 4 flag tells the test runner to allow up to 4 tests to run simultaneously. If you omit the flag, Go defaults to the number of logical CPUs available.
Key constraints to remember:
- First Call:
t.Parallel()must be the first line of the test function. If you perform any setup or logging before it, the test will panic. - Synchronization: Parallel tests share the same process memory. If your tests access global variables or shared resources, you must use mutexes or channels to prevent race conditions.
- Blocking: If a test blocks indefinitely (e.g., waiting for a channel that never closes), it will block the entire test suite from finishing. Use
t.SetDeadlineort.SetTimeoutto prevent hanging. - Dependencies: Do not rely on the order of execution. Parallel tests run in an undefined order, and a parallel test cannot depend on the side effects of another test.
If you need to run a specific test in isolation to debug a race condition, use go test -run TestName -parallel 1 to force sequential execution.