The test functions in GoLang

In this post, we will discuss some ways we can create test functions in Go. Test functions are essential but it not always obvious how we can run tests in a better and efficient way. Writing the same code over and over again can take a huge amount of time. This post aims to provide some insights into what can be done to reduce this problem.

Examples of test functions

Here are some of the ways a test function can be created.

1. Using test functions directly

We can simply use test function just checking values one by one. This is the most straightforward method that can be used. It is although not very efficient for running multiple tests. Here is the function that we are going to test.

// main.go
package main

func Greet(name string) string {
	if name == "" {
		return "Hello, world"
	} else {
		return "Hello, " + name
	}
}

func main() {
}

Now, the test file should be named as filename_test.go. The file contains the test functions of the form TestXXX(t *testing.T). Here is the test methods for our code:

package main

import "testing"

func TestGetVal(t *testing.T) {
	Check(Greet("John"), "Hello, John", t)
	Check(Greet(""), "Hello, world", t)
}

func Check(ret, expected string, t *testing.T) {
	if ret != expected {
		t.Error("Expected:", expected, "Got:", ret)
	} else {
		t.Log("SUCCESS")
	}
}

After running the go test it will produce the correct output.

2. Testing using a table of values

We can use a table to store the test values and run tests using a loop. This will significantly reduce the amount of code needed to run all the tests. Also when adding new tests we will simply need to update the table of values.

This code checks a simple add function that is defined in the main file.

package main

import "testing"

func TestAdd(t *testing.T) {
	tables := []struct {            // declare table of data
		x int                   // {x, y, n}       x + y = n
		y int
		n int
	}{
		{10, 10, 20},
		{11, 23, 34},
		{7, 9, 16},
		{3, 4, 7},
	}

	for _, table := range tables {
		total := Add(table.x, table.y)
		CheckInt(total, table.n, t)
	}
}

func CheckStr(ret, expected string, t *testing.T) {
	if ret != expected {
		t.Error("Expected:", expected, "Got:", ret)
	} else {
		t.Log("SUCCESS")
	}
}

func CheckInt(ret, expected int, t *testing.T) {
	if ret != expected {
		t.Error("Expected:", expected, "Got:", ret)
	} else {
		t.Log("SUCCESS")
	}
}

The loop runs through each value and does testing for each triplet. The only problem is that the data structure should be well defined for the test to work properly.

Coverage

The go test function is also able to provide coverage for the code. The -cover flag helps the tool do so.