Run Go Package Tests Without Losing the Useful Signals

A green go test run can still be hiding a stale cached result, and a red one can be a vet finding rather than a real test failure. This guide runs tests for the current package, expands the check to every package in a module, and makes sense of the output when something fails.

The examples use the installed Go command, version go1.26.1, with the Debian golang-go package recorded as 2:1.22~2build1 on this machine. Allow about fifteen minutes for a first pass, plus whatever time a failing test actually needs.

You need a shell, a Go project with a go.mod file or a package directory, and permission to read its source. These checks are normally unprivileged. Do not use sudo to run tests: root can hide permission problems and can leave root-owned build or test artefacts in a working tree.

1. Check the command and project context

Start by confirming which Go executable will run and whether the current directory belongs to a module:

$ command -v go
/home/linuxbrew/.linuxbrew/bin/go
$ go version
go version go1.26.1 linux/amd64
$ go env GOMOD
/path/to/project/go.mod

If GOMOD prints /dev/null, change into the project directory or use a package path your Go installation can resolve. A test run is easier to reproduce when the command, module and package pattern are all explicit.

Checkpoint: run go test -h. It should show the form go test [build/test flags] [packages] [build/test flags & test binary flags]. If the command is missing, stop and install Go through your normal system package or toolchain process rather than copying a binary into the project.

2. Run the current package

With no package argument, go test uses local directory mode. It compiles the package and its matching *_test.go files, runs the resulting test binary, and prints a final status:

$ go test
ok    example.com/widget    0.018s

The exact package name and duration will differ. A successful exit status is the important signal for a script. Test files can contain unit tests, benchmarks, fuzz tests and examples; ordinary test functions are discovered by Go's testing conventions, not by passing a file name on this command line.

For a test-by-test trace, add -v:

$ go test -v
=== RUN   TestParseConfig
--- PASS: TestParseConfig (0.00s)
PASS
ok    example.com/widget    0.019s

Verbose output is useful while diagnosing a failure, but it can be noisy in continuous integration logs. Start without it when the package has many tests, then add it when you need the test names and logged messages.

3. Test every package in the module

Use the recursive package pattern ./... from the module root:

$ go test ./...
ok    example.com/widget           0.021s
ok    example.com/widget/internal  0.006s

Each listed package gets its own test binary, and in package list mode, passing results can be cached. A line ending in (cached) means Go reused a previous successful result instead of running that package's binary again, which is handy during routine development but distracting when you are checking a changed environment or a test that reads external state.

Force a fresh run with -count=1:

$ go test -count=1 ./...
ok    example.com/widget           0.022s
ok    example.com/widget/internal  0.007s

The cache is not a general result store: Go only caches successful package tests when the command uses the restricted cacheable flags. A non-cacheable test or build flag disables reuse, but -count=1 is the clearest choice when you want that decision visible in a script or review.

4. Narrow the run while investigating

Use -run with a regular expression to select matching test names:

$ go test -run '^TestParseConfig$' -v
=== RUN   TestParseConfig
--- PASS: TestParseConfig (0.00s)
PASS
ok    example.com/widget    0.003s

Anchor the expression when you want one exact test. Without the anchors, a pattern such as Parse can match several names. A filtered pass does not prove the package is healthy, so rerun the complete package or module after the focused check.

Use -short when the project defines tests that deliberately skip expensive or long-running work in short mode:

$ go test -short ./...

Tip: read the project documentation before treating a short run as a release check. It is a scope reduction, not a stronger test result.

5. Read failures and vet errors separately

A failing test normally prints its name, the test's diagnostic, a final FAIL line, and a non-zero exit status. The command writes test output to standard output, including anything a test itself wrote to standard error, while build errors remain on standard error. Preserve both streams when collecting logs:

$ go test ./... >test.log 2>build-errors.log
$ status=$?
$ printf 'go test status: %s\n' "$status"
go test status: 1

Keep both files until you know which failure occurred. If you only capture standard error, you can miss the assertion that explains a failed test. Save the shell variable immediately: another command changes $?.

As part of building the test binary, this installed command also runs a high-confidence subset of go vet, covering checks such as atomic, printf, errorsas and stringintconv. A vet finding prevents the test binary from running at all, so an apparent test failure may actually be a source diagnostic. Fix the reported code and rerun the same command. Use -vet=off only when you have a specific reason and a separate vet step; use -vet=all when you deliberately want the full vet checks.

Common traps

Done means