Skip to content
gohacks.dev
Testing

Run a Single Go Test or Subtest From the Command Line

Run one Go test or subtest with go test -run: how the regular expression matches each slash level, anchors, names with spaces, -list and -skip.

4 min read
Summarize in AI
Flat illustration of a test report with one failing test.

When one test fails you want to run that test alone, quickly, with its output visible. go test -run does that, and it is worth knowing exactly how the pattern is interpreted, because the first thing most people try runs more than they expected.

Tested with Go 1.25.6, macOS on Apple Silicon (arm64)

The lab has three tests: TestParse with subtests empty, short and long, TestParseHeader with none, and TestRender with subtests empty and full page.

pick_test.goGo
package main

import "testing"

func TestParse(t *testing.T) {
	for _, n := range []string{"empty", "short", "long"} {
		t.Run(n, func(t *testing.T) {})
	}
}

func TestParseHeader(t *testing.T) {}

func TestRender(t *testing.T) {
	t.Run("empty", func(t *testing.T) {})
	t.Run("full page", func(t *testing.T) {})
}
main.goGo
package main

func main() {}
Shell
show() { echo "\$ go test $*"; go test -count=1 -v "$@" . 2>&1 | grep -E '^(=== RUN|ok|FAIL|no tests)|^TestPick|^Test' | sed -E 's/^=== RUN +//; s/[[:space:]]+[0-9.]+s$//'; }
show -run 'TestParse'
show -run '^TestParse$'
show -run 'TestParse/short'
show -run '/empty'
show -run 'TestRender/full_page'
show -run 'Parse$/^l'
echo '$ go test -list .'
go test -list . . | grep -v '^ok'
echo '$ go test -skip TestParseHeader -v'
go test -count=1 -skip 'TestParseHeader' -v . 2>&1 | grep -E '^=== RUN' | sed -E 's/^=== RUN +//'
Text
$ go test -run TestParse
TestParse
TestParse/empty
TestParse/short
TestParse/long
TestParseHeader
ok  	example.test/lab
$ go test -run ^TestParse$
TestParse
TestParse/empty
TestParse/short
TestParse/long
ok  	example.test/lab
$ go test -run TestParse/short
TestParse
TestParse/short
TestParseHeader
ok  	example.test/lab
$ go test -run /empty
TestParse
TestParse/empty
TestParseHeader
TestRender
TestRender/empty
ok  	example.test/lab
$ go test -run TestRender/full_page
TestRender
TestRender/full_page
ok  	example.test/lab
$ go test -run Parse$/^l
TestParse
TestParse/long
ok  	example.test/lab
$ go test -list .
TestParse
TestParseHeader
TestRender
$ go test -skip TestParseHeader -v
TestParse
TestParse/empty
TestParse/short
TestParse/long
TestRender
TestRender/empty
TestRender/full_page

The pattern is a regular expression

-run takes a regular expression and runs the tests whose names match it. It is not anchored, so -run TestParse matches TestParse and TestParseHeader, as the first block shows. To select exactly one top-level test, anchor it: -run '^TestParse$' ran TestParse and its three subtests and nothing else. Quote the pattern; $ and ^ mean something to the shell.

One pattern per slash level

For subtests, the pattern is split on slashes, and each part is matched against the corresponding level of the name. -run 'TestParse/short' means: top-level name matches TestParse, subtest name matches short. In the output only the short subtest of TestParse ran, not empty or long.

You can leave a level empty to match anything: -run '/empty' ran the empty subtest of both TestParse and TestRender. That is handy for a name you reuse across tests.

Each level has its own regular expression, so anchors work per level: -run 'Parse$/^l' selected TestParse (and not TestParseHeader, because of the $) and, inside it, the subtest starting with l, which is long.

Spaces in subtest names

The subtest named full page is selected as full_page: Go rewrites spaces in subtest names to underscores, and the pattern must use the rewritten name. -run 'TestRender/full_page' ran it. Other unprintable characters are escaped too, and -v output shows the names you should type.

The gotcha with tests that have no subtests

Look at the third and fourth blocks. -run 'TestParse/short' printed TestParseHeader as well. TestParseHeader has no subtests, and its top-level name matches the first part of the pattern, so it runs; there is nothing at the second level to filter. The same happened with -run '/empty'. A function whose top-level name matches runs completely; the later parts of the pattern only filter subtests that exist. Anchor the first part (^TestParse$/short) if you want only one test.

Listing and skipping

go test -list . prints the names of the top-level tests, benchmarks, fuzz tests and examples that match a pattern, without running anything. It lists top-level names only, since subtests exist only at run time. Use it to check a pattern, or in a script that runs tests one by one.

-skip (Go 1.20) is the inverse of -run: tests matching the pattern are not run. -skip 'TestParseHeader' ran everything else, subtests included. It accepts the same slash syntax. The two combine: -run Parse -skip Header.

Habits

  • Add -count=1 when you rerun a test you did not change, to avoid a cached "ok" (the basics).
  • Add -v to see the test names and logs, and -race if goroutines are involved.
  • When a table test fails, the failure output names the subtest, so copy it into -run (with underscores) to iterate on that row (table-driven tests).
  • In an editor, use the "run test" action; it passes an anchored -run for you.
  • For a package other than the current one, add the path: go test -run '^TestX$' ./internal/store.

The pattern syntax is documented in the testing flags reference and the matching rules under T.Run. For parallel subtests and ordering, see subtests and parallel tests.

Also inBasics
Taggedquick tip
Share

Keep reading

Get new articles by email

We send one email when a new article is published. No spam.

Unsubscribe in one click. No spam, ever.