Skip to content
← Back to Community
Testing in Go
Profile icon
ShaikhulIslam

Go testing support is awesome. It has a subcommand go test that looks for *_test.go files in package folder and run all test functions that starts with Test* prefix and report success or error.

All test functions should follow this naming convention

func TestXXXX(t *testing.T) { }

t param is used to report success/failure messages. Some useful methods are

t.Errorf // to report an error t.Logf // to log something t.Skip // skip a test

More on testing package are here

Say, we have a package hello that defines a simple Hello function as follows that we want to add test

// file hello.go package hello func Hello() string { return "Hello World" }

We need to create hello_test.go file in same directory

// file hello_test.go package hello // import testing package import "testing" func TestHello(t *testing.T) { want := "Hello World" if got := Hello(); got != want { // report mismatch t.Errorf("Hello() = %q, want %q", got, want) } }

Now we have tests for our hello package. To test we need go to the folder hello/

$ ls hello.go hello_test.go

If we do go test it will run the test runner and execute all Test* functions and report success/error

$ go test PASS ok main/hello 0.011s

To see which tests were run we can use verbose option go test -v

$ go test -v === RUN TestHello --- PASS: TestHello (0.00s) PASS ok main/hello 0.029s

We can also specify a substring of specific test function go test -v -run="Hello" and test runner will look for test functions that uses the substring

$ go test -v -run="Hello" === RUN TestHello --- PASS: TestHello (0.00s) PASS ok main/hello 0.027s

Table driven Testing

Now we added a Greet function that takes a param and return a greet message

func Greet(name string) string { return fmt.Sprintf("Hello %s", name) }

Now we want to test Greet function but with different test cases, we can create a slice of struct with input, output definition and check results in a loop. This is called table driven testing.

func TestGreet(t *testing.T) { testCases := []struct { testDesc string input string output string } { {"Empty string", "", "Hello "}, {"ASCII string", "World", "Hello World"}, {"Unicode string", "世界", "Hello 世界"}, } for _, testCase := range testCases { t.Run(testCase.testDesc, func(t *testing.T) { if got := Greet(testCase.input); got != testCase.output { t.Errorf("Hello() = %q, want %q", got, testCase.output) } }) } }

Here we uses an anonymous struct that has testDest, input and output fields, and then we create a slice of struct with our test cases.
t.Run takes an anynymous function which is similar to our TestHello function.

Go does not provide any built assertion library but there are plenty out there to import. one is testify/assert

Once we import it from github.com/stretchr/testify/assert we can use differnt assertion functions like these

assert.Equal(t, expected, actual) assert.NotEqual(t, expected, actual) assert.True(t, boolStmt) assert.False(t, boolStmt)

Now we can run tests against this test as go test -v -run="Greet"

$ go test -v -run="Greet" === RUN TestGreet === RUN TestGreet/Empty_string === RUN TestGreet/ASCII_string === RUN TestGreet/Unicode_string --- PASS: TestGreet (0.00s) --- PASS: TestGreet/Empty_string (0.00s) --- PASS: TestGreet/ASCII_string (0.00s) --- PASS: TestGreet/Unicode_string (0.00s) PASS ok main/hello 0.009s
Voters
Profile icon
Guiwoo
Profile icon
Golfsierra007
Profile icon
Mawuli
Profile icon
BotsBoots
Profile icon
ShaikhulIslam