Standard Library

Testing in Go

Go has built-in support for testing, making it easy to write, organize, and execute tests. The standard testing package provides everything you need for unit testing, benchmarks, and examples. In this article, we’ll explore how to test Go code effectively, covering basic tests, table-driven testing, mocking, and best practices.

Basics of Testing in Go

Creating a Test File

Test files are named with the _test.go suffix. If the source file is math.go, the test file should be math_test.go.

Writing a Basic Test

Each test function should start with Test preffix and it should take a single parameter of type *testing.T.

package main
 
import "testing"
 
func Add(a, b int) int {
	return a + b
}
 
func TestAdd(t *testing.T) {
	result := Add(2, 3)
	expected := 5
 
	if result != expected {
		t.Errorf("Add(2, 3) = %d; want %d", result, expected)
	}
}

Run the code in your browser (opens in a new tab), without installation.

Execute the following command for running the tests

go test ./...

Testing for Errors

Functions that return errors should be tested to ensure correct error handling.

func Divide(a, b int) (int, error) {
	if b == 0 {
		return 0, fmt.Errorf("division by zero")
	}
	return a / b, nil
}
 
func TestDivide(t *testing.T) {
	tests := []struct {
		a, b        int
		expected    int
		expectError bool
	}{
		{10, 2, 5, false},
		{10, 0, 0, true},
	}
 
	for _, tt := range tests {
		result, err := Divide(tt.a, tt.b)
		if tt.expectError {
			if err == nil {
				t.Errorf("expected error but got none")
			}
		} else {
			if err != nil {
				t.Errorf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("Divide(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
			}
		}
	}
}

Mocking in Go

Mocking is useful for testing interactions with external systems like APIs or databases. Use interfaces to abstract dependencies and create mock implementations for testing.

type DataFetcher interface {
	FetchData() (string, error)
}
 
func GetData(fetcher DataFetcher) (string, error) {
	return fetcher.FetchData()
}
 
// Mock implementation
type MockFetcher struct{}
 
func (m MockFetcher) FetchData() (string, error) {
	return "mocked data", nil
}
 
func TestGetData(t *testing.T) {
	mock := MockFetcher{}
	data, err := GetData(mock)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if data != "mocked data" {
		t.Errorf("expected 'mocked data', got %s", data)
	}
}

Run this code in your browser (opens in a new tab)

Benchmarks in Go

Benchmarking allows you to measure the performance of functions. Benchmark functions start with Benchmark and take a *testing.B parameter.

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

Run benchmarks:

go test -bench=.

Examples in Go

Go allows you to write example functions that serve as documentation and can also be executed as tests.

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

Run this code in your browser (opens in a new tab).

Test Coverage

Test coverage is a measure of how much of your code is executed when your tests run. In Go, the go test command provides built-in support for measuring and reporting test coverage, making it easier to ensure your tests cover critical parts of your codebase.

To measure test coverage in Go, use the -cover flag with the go test command:

go test -cover ./...

Output

ok  	myapp	0.005s	coverage: 85.0% of statements

This output indicates that 85% of your code statements were executed during the tests.

Generate Detailed Coverage Reports

For more detailed insights, use the -coverprofile flag to generate a coverage report

go test -coverprofile=coverage.out ./...

The coverage.out file contains detailed information about which lines were covered.

You can then visualize this report in the terminal or as an HTML file.

Terminal Visualization

go tool cover -func=coverage.out

Output

myapp/main.go:34:	Add		100.0%
myapp/util.go:12:	Multiply	85.7%
total:			(statements)	90.0%

HTML Visualization

go tool cover -html=coverage.out

This opens an interactive HTML report in your default browser, highlighting covered and uncovered code lines.