This post documents some testing I did around whether unit tests in Golang are run in parallel.
TLDR: Tests in a given package run serially, unless t.Parallel()
is specified.
To test this, I created two files in a directory named gotest
:
$ ls
one_test.go two_test.go
// one_test.go
package main
import (
"fmt"
"testing"
"time"
)
func TestOne(t *testing.T) {
fmt.Println("1 starts:", time.Now().String())
time.Sleep(5 * time.Second)
fmt.Println("1 ends:", time.Now().String())
}
// two_test.go
package main
import (
"fmt"
"testing"
"time"
)
func TestTwo(t *testing.T) {
fmt.Println("2 starts:", time.Now().String())
fmt.Println("2 ends:", time.Now().String())
}
When I ran the tests, you can see that TestOne
blocked TestTwo
from running for five seconds:
$ go test -v -count 1 one_test.go two_test.go
=== RUN TestOne
1 starts: 2024-10-18 07:56:48.504461 -0700 PDT m=+0.001203001
1 ends: 2024-10-18 07:56:53.505833 -0700 PDT m=+5.002603251
--- PASS: TestOne (5.00s)
=== RUN TestTwo
2 starts: 2024-10-18 07:56:53.506276 -0700 PDT m=+5.003046710 <---- Does not start until TestOne finishes
2 ends: 2024-10-18 07:56:53.506289 -0700 PDT m=+5.003059210
--- PASS: TestTwo (0.00s)
PASS
ok command-line-arguments 5.400s
[07:56] widget ~/.../go/gotest $
Interestingly, it appears that the order in which I specify test files matters. If I reverse them, TwoTest
runs first and is not blocked:
$ go test -v -count 1 two_test.go one_test.go
=== RUN TestTwo <-------------- Starts first because the file order changed!
2 starts: 2024-10-18 07:58:01.635143 -0700 PDT m=+0.000389543
2 ends: 2024-10-18 07:58:01.635226 -0700 PDT m=+0.000473001
--- PASS: TestTwo (0.00s)
=== RUN TestOne
1 starts: 2024-10-18 07:58:01.635245 -0700 PDT m=+0.000491960
1 ends: 2024-10-18 07:58:06.636325 -0700 PDT m=+5.001599543
--- PASS: TestOne (5.00s)
PASS
ok command-line-arguments 5.204s
If I modify the tests to add t.Parallal()
…
// one_test.go
package main
import (
"fmt"
"testing"
"time"
)
func TestOne(t *testing.T) {
t.Parallel() // this is new
fmt.Println("1 starts:", time.Now().String())
time.Sleep(5 * time.Second)
fmt.Println("1 ends:", time.Now().String())
}
// two_test.go
package main
import (
"fmt"
"testing"
"time"
)
func TestTwo(t *testing.T) {
t.Parallel() // this is new
fmt.Println("2 starts:", time.Now().String())
fmt.Println("2 ends:", time.Now().String())
}
…then the tests run in parallel, which makes sense:
[07:59] widget ~/.../go/gotest $ go test -v -count 1 one_test.go two_test.go
=== RUN TestOne
=== PAUSE TestOne
=== RUN TestTwo
=== PAUSE TestTwo
=== CONT TestOne
=== CONT TestTwo
1 starts: 2024-10-18 07:59:38.016855 -0700 PDT m=+0.001054334
2 starts: 2024-10-18 07:59:38.016932 -0700 PDT m=+0.001131209
2 ends: 2024-10-18 07:59:38.017105 -0700 PDT m=+0.001304543
--- PASS: TestTwo (0.00s)
1 ends: 2024-10-18 07:59:43.018119 -0700 PDT m=+5.002346709
--- PASS: TestOne (5.00s)
PASS
ok command-line-arguments 5.209s
[07:59] widget ~/.../go/gotest $
This blog post was helpful when researching this.