Go parallel test — capture range variable in test table

Tung Nguyen
2 min readMay 8, 2023

Problem

First of all, let’s take a look on a pretty simple test of a sum as below. The test just has two test cases, one expects a negative result and another one expects a positive result. However, there is a mistake in the first test case (“Must be negative”), the expected got value must be -5 instead 5.

package main

import (
"testing"
)

func TestParallelismWithTestTable(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
v int
go int
}{
{
name: "Must be negative",
v: -10,
got: 5,
},
{
name: "Must be positive",
v: 5,
got: 10,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
result := 5 + tc.v
if tc.got != result {
t.Errorf("%d != %d", tc.got, result)
}
})
}
}
--- PASS: TestParallelismWithTestTable (0.00s)
--- PASS: TestParallelismWithTestTable/Must_be_negative (0.00s)
--- PASS: TestParallelismWithTestTable/Must_be_positive (0.00s)
PASS

Check it on playground: https://go.dev/play/p/mUmfoCBH8Ad

Unfortunately, the test result tells that both test case pass, all good in our code. This is a very dangerous mistake in Go test because the test gives us a fake result that our code is perfect but in fact there are bugs there.

Reason

Test runs are created in parallel and variable tc is already assigned to the last test case when test runs are executed. Therefore, both test runs are done on the last test case and they all pass of-course.

How to avoid the problem

Similar to the common problem of executing go routines with a range variable, the range variable tc must be captured.

package main

import (
"testing"
)

func TestParallelismWithTestTable(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
v int
got int
}{
{
name: "Must be negative",
v: -10,
got: 5,
},
{
name: "Must be positive",
v: 5,
got: 10,
},
}
for _, tc := range testCases {
// CAPTURE THE RANGE VARIABLE tc
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
result := 5 + tc.v
if tc.got != result {
t.Errorf("%d != %d", tc.got, result)
}
})
}
}
--- FAIL: TestParallelismWithTestTable (0.00s)
--- FAIL: TestParallelismWithTestTable/Must_be_negative (0.00s)
--- PASS: TestParallelismWithTestTable/Must_be_positive (0.00s)
FAIL

Check it on Go play ground https://go.dev/play/p/kDNi4ACyb7A

Now the test works as we expect.

--

--

Tung Nguyen

A coding lover. Mouse and keyboard are my friends all day long. Computer is a part of my life and coding is my cup of tea.