oinume journal

Scratchpad of what I learned

go test in practice

This blog post describes basics and practical examples of go test. Go’s automated test mechanism is well designed and easy to use. I’ll show you some techniques of go test in this article.

What is go test

go test is a command to run automated tests of go packages.

  • Automated test must be defined in _test.go file
  • Automated test function must start with Test prefix

Example: stack

I implement a stack as real world example to explain go test. stack package provides stack.go. If you want to write tests for stack.go, create a file named stack_test.go. The source code is in GitHub repository.

go test [packages]

First of all, let’s test a simple function stack.NewIntStack.

package stack

import "testing"

func TestNewIntStack(t *testing.T) {
    istack := NewIntStack()
    if istack == nil {
        t.Error("NewIntStack() returns nil")
    }
}

The test checks NewIntStack returns non nil. To run the test, type go test ./stack. You’ll get following output. It means the test succeeded.

go test ./stack

ok      github.com/oinume/go-test-in-practice/stack       0.136s

go test -v

-v flag enables verbose mode. You can get a message TestNewIntStack finished by running with -v flag.

func TestNewIntStack(t *testing.T) {
    istack := NewIntStack()
    if istack == nil {
        t.Error("NewIntStack() returns nil")
    }
    t.Log("TestNewIntStack finished") // This message is output only in verbose mode
}
go test -v ./stack

=== RUN   TestNewIntStack
--- PASS: TestNewIntStack (0.00s)
        stack_test.go:10: TestNewIntStack finished
PASS
ok      github.com/oinume/go-test-in-practice/stack       0.132s

all outputs in STDOUT are printed in verbose mode. You can use t.Log or t.Logf if you want to print a message with line number.

If you want to do something only when verbose mode, You can use testing.Verbose() in your test code.

go test -short

You can use -short flag to skip long-running tests. You can refer the flag is on or off by testing.Short() in your test.

Example:

func TestIntStack_PushALot(t *testing.T) {
    if testing.Short() {
        t.Skip("Skip pushing a lot of numbers to a stack")
    }
    istack := NewIntStack()
    for i := 0; i < 10000000; i++ {
        istack.Push(i)
    }
}

go test -run

-run flag is used to specify tests to run. If you have test functions TestNewIntStack and TestIntStack_PushALot, you want to run only TestIntStack_PushALot. You’ll save time with -run flag in order to avoid running whole tests.

Example:

go test -run TestIntStack_PushALot ./stack

=== RUN   TestIntStack_PushALot
--- PASS: TestIntStack_PushALot (1.01s)
PASS
ok      github.com/oinume/go-test-in-practice/stack       1.156s

reflect.DeepEqual

You can use reflect.DeepEqual to compare two values of structs. Following example ensures istack1 and istack2 are the same.

func TestIntStack_Compare(t *testing.T) {
    istack1 := NewIntStack()
    istack2 := NewIntStack()
    for i := range []int{1, 2, 3} {
        istack1.Push(i)
        istack2.Push(i)
    }
    if !reflect.DeepEqual(istack1, istack2) {
        t.Errorf("Stacks must be the same: istack1.Size=%d, istack2.Size=%d", istack1.Size(), istack2.Size())
    }
}

TestMain

TestMain is a main function in automated tests. Sometimes it is necessary for a test program to do extra setup or teardown before or after testing. If func TestMain(m *testing.M) function exists in your package, the generated test will call TestMain(m) instead of running the tests directly. This is an example to set up and tear down with TestMain.

func TestMain(m *testing.M) {
    // Set up something for tests
    status := m.Run()
    // Tear down something for tests
    os.Exit(status)
}

And more

go test has much more features like benchmark, example test, etc. You’ll find them out in document of testing package. There are also good slides of testing like Advanced Testing with Go // Speaker Deck.