Skip to main content

Writing Tests in Go

In this article, we'll be exploring how to write tests in Go, a crucial skill for any Go developer. We'll start from the basics and gradually build up to more complex aspects of writing tests. Knowing how to write effective tests can help you catch bugs early and ensure that your code is working as expected.

The Basics of Testing in Go

In Go, each test is associated with a specific source file. For example, if you have a source file named main.go, the corresponding test file would be main_test.go. All test files must end with _test.go.

Each test function in Go should start with the word Test followed by a description of what the function tests. The function should take a single argument, a pointer to testing.T. Here's an example:

func TestSum(t *testing.T) {
total := Sum(2, 3)
if total != 5 {
t.Errorf("Sum was incorrect, got: %d, want: %d.", total, 5)
}
}

In this example, the Sum function is supposed to return the sum of the two arguments it receives. If it doesn't return the expected result, the t.Errorf function is called to log an error message.

Running Tests

To run your tests, use the go test command followed by the name of the package that contains your test. For example, if your package is named main, you would run go test main.

More Advanced Testing

Table-Driven Tests

When you want to test a function with several different inputs, you can use table-driven tests. In a table-driven test, you define a table (which is just a slice of structs) where each struct represents a test case. Here's an example:

func TestSum(t *testing.T) {
testCases := []struct {
a, b, expected int
}{
{1, 2, 3},
{4, -5, -1},
{0, 0, 0},
{-2, -2, -4},
}

for _, testCase := range testCases {
total := Sum(testCase.a, testCase.b)
if total != testCase.expected {
t.Errorf("Sum(%d, %d) was incorrect, got: %d, want: %d.", testCase.a, testCase.b, total, testCase.expected)
}
}
}

In this example, the Sum function is tested with four different pairs of inputs.

Testing for Errors

If your function is supposed to return an error under certain conditions, you can test for this using the Errorf function. Here's an example:

func TestDivide(t *testing.T) {
_, err := Divide(10, 0)
if err == nil {
t.Errorf("Expected an error but didn't get one")
}
}

In this example, the Divide function is expected to return an error when the second argument is zero. If it doesn't, the test fails.

Conclusion

Writing tests is an essential part of developing robust, reliable software. By writing tests, you can catch bugs early, ensure that your functions behave as expected, and make your code easier to maintain. As you gain more experience with Go, you'll develop a deeper understanding of how to write effective tests. Happy coding!