Skip to content

Instantly share code, notes, and snippets.

@myshkin5
Last active September 30, 2022 21:32
Show Gist options
  • Save myshkin5/56c71b6117b06cd25c5c01765e40fcb9 to your computer and use it in GitHub Desktop.
Save myshkin5/56c71b6117b06cd25c5c01765e40fcb9 to your computer and use it in GitHub Desktop.
Running Go sub-tests
package subtests_test
import (
"fmt"
"testing"
)
func TestSomething(t *testing.T) {
fmt.Println("Something")
sliceTestCases := []struct {
name string
param string
}{
{name: "test1", param: "param1"},
{name: "test2", param: "param2"},
}
for _, tc := range sliceTestCases {
t.Run(tc.name, func(t *testing.T) {
fmt.Println(tc.name, tc.param)
})
}
t.Run("slice", func(t *testing.T) {
testCases := []struct {
name string
param string
}{
{name: "test1", param: "param1"},
{name: "test2", param: "param2"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fmt.Println(tc.name, tc.param)
})
}
})
mapTestCases := map[string]struct {
param string
}{
"test1": {param: "param1"},
"test2": {param: "param2"},
}
for name, tc := range mapTestCases {
t.Run(name, func(t *testing.T) {
fmt.Println(name, tc.param)
})
}
t.Run("map", func(t *testing.T) {
testCases := map[string]struct {
param string
}{
"test1": {param: "param1"},
"test2": {param: "param2"},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
fmt.Println(name, tc.param)
})
}
})
t.Run("child", func(t *testing.T) {
fmt.Println("child")
t.Run("sub-child", func(t *testing.T) {
fmt.Println("sub-child")
t.Run("sub-sub-child", func(t *testing.T) {
fmt.Println("sub-sub-child")
})
})
})
}
$ go test -v ./...
=== RUN   TestSomething
Something
=== RUN   TestSomething/test1
test1 param1
=== RUN   TestSomething/test2
test2 param2
=== RUN   TestSomething/slice
=== RUN   TestSomething/slice/test1
test1 param1
=== RUN   TestSomething/slice/test2
test2 param2
=== RUN   TestSomething/test1#01
test1 param1
=== RUN   TestSomething/test2#01
test2 param2
=== RUN   TestSomething/map
=== RUN   TestSomething/map/test1
test1 param1
=== RUN   TestSomething/map/test2
test2 param2
=== RUN   TestSomething/child
child
=== RUN   TestSomething/child/sub-child
sub-child
=== RUN   TestSomething/child/sub-child/sub-sub-child
sub-sub-child
--- PASS: TestSomething (0.00s)
    --- PASS: TestSomething/test1 (0.00s)
    --- PASS: TestSomething/test2 (0.00s)
    --- PASS: TestSomething/slice (0.00s)
        --- PASS: TestSomething/slice/test1 (0.00s)
        --- PASS: TestSomething/slice/test2 (0.00s)
    --- PASS: TestSomething/test1#01 (0.00s)
    --- PASS: TestSomething/test2#01 (0.00s)
    --- PASS: TestSomething/map (0.00s)
        --- PASS: TestSomething/map/test1 (0.00s)
        --- PASS: TestSomething/map/test2 (0.00s)
    --- PASS: TestSomething/child (0.00s)
        --- PASS: TestSomething/child/sub-child (0.00s)
            --- PASS: TestSomething/child/sub-child/sub-sub-child (0.00s)
PASS
ok  	subtests	0.115s

Specific tests can be run by specifying the -run option with any of the strings following === RUN from above (substrings appear to match):

$ go test -v ./... -run Something/s
=== RUN   TestSomething
Something
=== RUN   TestSomething/test1
test1 param1
=== RUN   TestSomething/test2
test2 param2
=== RUN   TestSomething/slice
=== RUN   TestSomething/slice/test1
test1 param1
=== RUN   TestSomething/slice/test2
test2 param2
=== RUN   TestSomething/test1#01
test1 param1
=== RUN   TestSomething/test2#01
test2 param2
--- PASS: TestSomething (0.00s)
    --- PASS: TestSomething/test1 (0.00s)
    --- PASS: TestSomething/test2 (0.00s)
    --- PASS: TestSomething/slice (0.00s)
        --- PASS: TestSomething/slice/test1 (0.00s)
        --- PASS: TestSomething/slice/test2 (0.00s)
    --- PASS: TestSomething/test1#01 (0.00s)
    --- PASS: TestSomething/test2#01 (0.00s)
PASS
ok  	subtests	0.112s

Note that where the top-level slice and map sub-tests use the same sub-test names things get a bit more confusing. You can run both test1 sub-tests:

$ go test -v ./... -run TestSomething/test1
=== RUN   TestSomething
Something
=== RUN   TestSomething/test1
test1 param1
=== RUN   TestSomething/test1#01
test1 param1
--- PASS: TestSomething (0.00s)
    --- PASS: TestSomething/test1 (0.00s)
    --- PASS: TestSomething/test1#01 (0.00s)
PASS
ok  	subtests	0.115s

And you can run just the second (assume any subsequent) sub-test:

$ go test -v ./... -run TestSomething/test1#01
=== RUN   TestSomething
Something
=== RUN   TestSomething/test1#01
test1 param1
--- PASS: TestSomething (0.00s)
    --- PASS: TestSomething/test1#01 (0.00s)
PASS
ok  	subtests	0.120s

But you can't run just the first test1 sub-test:

$ go test -v ./... -run TestSomething/test1#00
=== RUN   TestSomething
Something
--- PASS: TestSomething (0.00s)
testing: warning: no tests to run
PASS
ok  	subtests	0.264s [no tests to run]

IDEA can target and run specific sub-test and sub-tests within sub-tests. It can also run specific slice-based table tests and map-based table tests. But to target any table test inside a sub-test you have to edit the test configuration and specify the pattern manually. When specifying something like -run TestSomething/slice/test1 from above, the pattern for IDEA will be ^\QTestSomething\E$/^\Qslice\E$/^\Qtest1\E$. I assume GoLand will behave similarly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment