← Back to articles

Learning Go (13): testing

Part 13 of my Go fundamentals notes: unit tests, table-driven tests, and benchmarks.

Unit testing in Go

1. Unit test cases

The go test command runs test code organized according to Go’s naming and signature conventions.

In a package directory, source files ending in _test.go are included in test builds.

These test files are not included in the ordinary executable, so keeping detailed tests does not enlarge the production binary.

The following names have different roles:

  1. Test: functional tests

  2. Benchmark: performance benchmarks

  3. Example: executable examples; fuzz tests use Fuzz

  4. TestMain: custom setup and teardown for the package’s tests

1.1. Writing a unit test

Here is a unit test example.

The package contains three Go files:

1、add.go

2、add_test.go

3、main.go

go

add.go defines Add, which adds two integers.

add_test.go imports testing and defines TestAdd to check Add and report failures.

import "testing"

func TestAdd(t *testing.T){
    re := add(1,2)
    if re!= 3{
        t.Errorf("add(1,2) = %d; want 3", re)
    }
}

Run go test in the package directory to execute the tests and inspect the results.

1.2. Skipping slow tests

Use t.Skip() when a test should be skipped, for example in a short test run.

go test -short enables short mode. Tests are skipped only when their own code checks testing.Short() and calls t.Skip().

It is up to the test author to decide which tests are too slow for short mode.

Here is an example of skipping a test.

func TestAdd(t *testing.T){
    if testing.Short(){
        t.Skip("skip this test")
    }
    // 下面是执行不到的
    re := add(1,2)
    if re!= 3{
        t.Errorf("add(1,2) = %d; want 3", re)
    }
}

testing.Short() lets tests distinguish ordinary and short runs.

2. Table-driven tests

When several inputs need to be tested, a table-driven test stores cases together and runs the same assertions for each. This avoids repetitive test code.

Here is a table-driven test example.

import "testing"

func TestAdd(t *testing.T){
    var tests = []struct{
        a int
        b int
        want int
    }{
        {1,2,3},
        {2,3,5},
        {3,4,7},
    }

    for _, tt := range tests{
        re := add(tt.a, tt.b)
        if re!= tt.want{
            t.Errorf("add(%d, %d) = %d; want %d", tt.a, tt.b, re, tt.want)
        }
    }
}

3. Performance benchmarks

Benchmarks measure the performance of functions where execution cost matters.

Benchmark support is also provided by the testing package.

Name benchmark functions with Benchmark followed by the operation being tested.

A benchmark function takes a *testing.B parameter.

Use go test -bench with a matching pattern, such as go test -bench ., to run benchmarks.

Here is a benchmark example.

import "testing"

func BenchmarkAdd(b *testing.B){
    a := 123
    b := 456
    c := 579


    for i:=0; i<b.N; i++{
        if actual := add(a,b); actual!= c{
            fmt.Printf("add(%d, %d) = %d; want %d", a, b, actual, c)
    }
}

b.ResetTimer() resets the benchmark timer so preparation work can be excluded from the measurement.

About this article’s date

The date recorded on the old site is retained; writing may have started earlier.

In this series · Go fundamentals

PreviousLearning Go (12): packages and modules ←