Skip to main content
The go test command automates testing the packages named by import paths. It compiles test files, runs test functions, and reports results.

Overview

Testing is a first-class citizen in Go. The go test command provides built-in support for unit tests, benchmarks, examples, and fuzz tests.

Basic Usage

go test [build/test flags] [packages] [build/test flags & test binary flags]
# Test current package
go test

# Test with verbose output
go test -v

# Test current package (explicit)
go test .

Test Files

Test File Naming

Test files must:
  • End with _test.go
  • Be in the same package directory
  • Not start with _ or .
// mypackage_test.go
package mypackage

import "testing"

func TestInternal(t *testing.T) {
    // Can access unexported functions
    result := internalFunc()
    if result != expected {
        t.Errorf("got %v, want %v", result, expected)
    }
}

Test Modes

Local Directory Mode

Invoked without package arguments:
go test
go test -v
  • Compiles package in current directory
  • Runs test binary immediately
  • Caching is disabled
  • Prints summary after completion

Package List Mode

Invoked with explicit package arguments:
go test ./...
go test example.com/myapp
  • Compiles and tests each listed package
  • Results are cached
  • Prints ‘ok’ for passing tests
  • Shows full output for failures

Common Test Flags

Test Selection

-run
regexp
Run only tests matching regexp
# Run specific test
go test -run TestMyFunction

# Run tests matching pattern
go test -run "Test.*Integration"

# Run subtests
go test -run TestMyFunc/subtest_name
-skip
regexp
Skip tests matching regexp
go test -skip "TestSlow|TestExternal"

Output Control

-v
flag
Verbose output - print all test names and results
go test -v
-json
flag
Output test results as JSON
go test -json
go test -json | tee test-results.json

Test Execution

-count
n
Run each test n times (default: 1)
# Disable test caching
go test -count=1

# Run tests multiple times
go test -count=10
-parallel
n
Maximum number of tests to run in parallel (default: GOMAXPROCS)
go test -parallel 4
-timeout
duration
Timeout for entire test execution (default: 10m)
go test -timeout 30s
go test -timeout 5m
-short
flag
Run in short mode - skip long-running tests
go test -short
In test code:
if testing.Short() {
    t.Skip("skipping test in short mode")
}
-failfast
flag
Stop after first test failure
go test -failfast

Coverage Flags

-cover
flag
Enable coverage analysis
go test -cover
-coverprofile
file
Write coverage profile to file
go test -coverprofile=coverage.out
-covermode
set|count|atomic
Set coverage mode
  • set: boolean (was this line executed?)
  • count: count how many times each line executed
  • atomic: like count, but correct for concurrent tests
go test -covermode=count -coverprofile=coverage.out

Writing Tests

Basic Test Function

1

Create Test File

Create a file ending in _test.go:
// math_test.go
package math

import "testing"
2

Write Test Function

Test functions must start with Test and take *testing.T:
func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5
    
    if result != expected {
        t.Errorf("Add(2, 3) = %d; want %d", result, expected)
    }
}
3

Run Tests

go test
go test -v

Table-Driven Tests

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive numbers", 2, 3, 5},
        {"negative numbers", -2, -3, -5},
        {"mixed signs", -2, 3, 1},
        {"zeros", 0, 0, 0},
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; want %d", 
                    tt.a, tt.b, result, tt.expected)
            }
        })
    }
}
Run specific subtests:
# Run all Add tests
go test -run TestAdd

# Run specific subtest
go test -run TestAdd/positive

Testing Methods

Report error but continue test:
t.Error("something went wrong")
t.Errorf("got %v, want %v", result, expected)
Report error and stop test immediately:
t.Fatal("critical failure")
t.Fatalf("setup failed: %v", err)
Print log output (only shown with -v or on failure):
t.Log("debug information")
t.Logf("processing item %d", i)
Skip test:
if runtime.GOOS == "windows" {
    t.Skip("skipping on Windows")
}
Register cleanup function:
tmpFile, err := os.CreateTemp("", "test")
if err != nil {
    t.Fatal(err)
}
t.Cleanup(func() {
    os.Remove(tmpFile.Name())
})

Benchmarks

Writing Benchmarks

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(2, 3)
    }
}

func BenchmarkComplexOperation(b *testing.B) {
    // Setup (not timed)
    data := setupData()
    
    b.ResetTimer() // Reset timer after setup
    
    for i := 0; i < b.N; i++ {
        ComplexOperation(data)
    }
}

Running Benchmarks

# Run all benchmarks
go test -bench=.

# Run specific benchmark
go test -bench=BenchmarkAdd

# Run benchmarks matching pattern
go test -bench="Complex.*"

Examples

Writing Examples

func ExampleAdd() {
    result := Add(2, 3)
    fmt.Println(result)
    // Output: 5
}

func ExampleAdd_negative() {
    result := Add(-2, -3)
    fmt.Println(result)
    // Output: -5
}

func ExamplePerson_String() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p)
    // Output: Alice (30 years old)
}
Examples serve as both documentation and tests.

Code Coverage

1

Generate Coverage Profile

go test -coverprofile=coverage.out
2

View Coverage Report

# Text summary
go tool cover -func=coverage.out

# HTML visualization
go tool cover -html=coverage.out
3

Coverage for Multiple Packages

go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Coverage Options

# Specify packages to cover
go test -coverpkg=./... -coverprofile=coverage.out

# Different coverage modes
go test -covermode=set -coverprofile=coverage.out
go test -covermode=count -coverprofile=coverage.out
go test -covermode=atomic -coverprofile=coverage.out

Test Caching

Go caches successful test results to avoid unnecessary reruns.

Cacheable Flags

Tests are cached when using only these flags:
  • -benchtime
  • -cpu
  • -coverprofile
  • -failfast
  • -fullpath
  • -list
  • -outputdir
  • -parallel
  • -run
  • -short
  • -skip
  • -timeout
  • -v

Disabling Cache

# Idiomatic way to disable cache
go test -count=1

Advanced Testing

Setup and Teardown

func TestMain(m *testing.M) {
    // Setup before all tests
    setup()
    
    // Run tests
    code := m.Run()
    
    // Teardown after all tests
    teardown()
    
    os.Exit(code)
}

Parallel Tests

func TestParallel(t *testing.T) {
    t.Parallel() // Mark test as parallelizable
    
    // Test code here
}

func TestParallelSubtests(t *testing.T) {
    tests := []struct{
        name string
        // ...
    }{
        // test cases
    }
    
    for _, tt := range tests {
        tt := tt // Capture range variable
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel()
            // Subtest code
        })
    }
}

Using testdata Directory

mypackage/
  ├── myfile.go
  ├── myfile_test.go
  └── testdata/
      ├── input.json
      └── expected.txt
func TestWithTestdata(t *testing.T) {
    data, err := os.ReadFile("testdata/input.json")
    if err != nil {
        t.Fatal(err)
    }
    // Use data in test
}

Test Compilation

Compile Test Binary

# Compile but don't run
go test -c

# Compile with custom output name
go test -c -o mytest.test

# Run compiled test binary
./mytest.test
./mytest.test -test.v -test.run TestSpecific

Binary Flags

Compiled test binaries accept -test.* flags:
./mytest.test -test.v
./mytest.test -test.run TestMyFunc
./mytest.test -test.bench=.
./mytest.test -test.cpuprofile=cpu.prof

CI/CD Integration

GitHub Actions

.github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-go@v5
        with:
          go-version: '1.21'
      
      - name: Run tests
        run: go test -v -race -coverprofile=coverage.out ./...
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage.out

Makefile

.PHONY: test
test:
	go test -v -race -coverprofile=coverage.out ./...

.PHONY: test-short
test-short:
	go test -short ./...

.PHONY: coverage
coverage: test
	go tool cover -html=coverage.out

.PHONY: bench
bench:
	go test -bench=. -benchmem ./...

Troubleshooting

# Disable caching
go test -count=1

# Or clear cache
go clean -testcache
# Increase timeout
go test -timeout 30m

# Check for infinite loops or deadlocks
go test -timeout 10s -v
# Run with race detector
go test -race

# May need more memory
GORACE="history_size=7" go test -race

See Also

go Command

Overview of go command

Building

Building Go programs

Benchmarking

Performance testing

Build docs developers (and LLMs) love