How to Use t.Run for Subtests in Go: Syntax and Examples
In Go, use
t.Run inside a test function to create subtests by giving each subtest a name and a function. This helps organize tests and run them separately with clear output. Each subtest runs as its own test with its own *testing.T context.Syntax
The t.Run method takes two arguments: a string name for the subtest and a function that receives a *testing.T parameter. Inside this function, you write the subtest code. Each subtest runs independently and reports its own result.
- t.Run(name string, f func(t *testing.T)) bool: Runs a subtest named
name. name: A descriptive name for the subtest.f: The function containing the subtest logic.
go
func TestExample(t *testing.T) {
t.Run("SubtestName", func(t *testing.T) {
// subtest code here
})
}Example
This example shows how to use t.Run to run two subtests that check if numbers are even or odd. Each subtest runs separately and reports its own pass/fail status.
go
package main import ( "testing" ) func isEven(n int) bool { return n%2 == 0 } func TestIsEven(t *testing.T) { tests := []struct { name string input int want bool }{ {"EvenNumber", 4, true}, {"OddNumber", 3, false}, } for _, tc := range tests { tc := tc // capture range variable t.Run(tc.name, func(t *testing.T) { if got := isEven(tc.input); got != tc.want { t.Errorf("isEven(%d) = %v; want %v", tc.input, got, tc.want) } }) } }
Output
=== RUN TestIsEven
=== RUN TestIsEven/EvenNumber
=== RUN TestIsEven/OddNumber
--- PASS: TestIsEven (0.00s)
--- PASS: TestIsEven/EvenNumber (0.00s)
--- PASS: TestIsEven/OddNumber (0.00s)
PASS
Common Pitfalls
A common mistake is not capturing the loop variable when using t.Run inside a loop. This causes all subtests to use the last loop value, leading to incorrect test results.
Always capture the loop variable inside the loop before calling t.Run by assigning it to a new variable.
go
for _, tc := range tests { // Wrong: using loop variable directly t.Run(tc.name, func(t *testing.T) { if got := isEven(tc.input); got != tc.want { t.Errorf("isEven(%d) = %v; want %v", tc.input, got, tc.want) } }) } // Correct way: for _, tc := range tests { tc := tc // capture loop variable t.Run(tc.name, func(t *testing.T) { if got := isEven(tc.input); got != tc.want { t.Errorf("isEven(%d) = %v; want %v", tc.input, got, tc.want) } }) }
Quick Reference
- t.Run(name, func(t *testing.T)): Run a subtest with a name and function.
- Subtests run independently and report results separately.
- Capture loop variables when using
t.Runinside loops. - Use subtests to organize related test cases clearly.
Key Takeaways
Use t.Run to create named subtests that run independently within a test function.
Always capture loop variables before calling t.Run inside loops to avoid bugs.
Subtests help organize tests and provide clear, separate output for each case.
Each subtest receives its own *testing.T, allowing isolated test control and reporting.