Page Content

Tutorials

Testing In Go Made Easy: From Unit to Integration Tests

Testing in Go

For your code to be reliable and of high quality, testing is a crucial step in the Go software development process. Go offers built-in tools that make developing and running tests easier, resulting in a productive and successful process that doesn’t take a lot of developer time.

The go test Command

To facilitate the process of developing and executing tests, Go comes with a unique application named go test.

Automatic Discovery: Tests in the current folder are automatically found and executed by the go test command.

File Naming Convention: The extension _test.go must be used at the end of test files. Only when a go test is executed does the Go compiler use the code in these files, which it knows to avoid during normal compilation (go install or go build).

Function Naming Convention: A descriptive name (such as TestAverage) must come after the word Test (case-sensitive) at the beginning of test functions.

Parameter: Test functions accept a single *testing.T argument.

Output: A test function returns PASS or FAIL as its outcome.

Caching: If there has been no modification to the code, the go test command can store results for quicker execution.

Verbose Output: The -v flag can be used with go test to generate output that is richer and more descriptive.

Running Specific Tests: A regular expression can be passed to the -run command-line option, which will only run tests whose function names match the pattern.

Writing Test Functions

An average function’s simple test function could resemble this:

package main
import "fmt"
// Average calculates the average of a slice of float64 numbers.
// This function was missing in the original code, causing the "undefined" error.
func Average(x []float64) float64 {
	total := float64(0)
	for _, v := range x {
		total += v
	}
	return total / float64(len(x))
}
func main() {
	var v float64
	v = Average([]float64{1, 2})
	fmt.Println("The average is", v)
}
  • In this example, TestAverage calls the Average function with known input ([]float64{1,2}) and checks if the output v matches the expected value 1.5.
  • To indicate an error to the go test program, use t.Error if the outcome is not what was anticipated.

In your terminal, find the directory that contains math.go and math_test.go. Then, enter the following command to run the test:

go test

You ought to observe results like this:

The average is 1.5

According to this, the test was successful.

Advanced Testing Patterns (Table-Driven Tests)

It is a good idea to test a wide range of input combinations. “Table-driven tests” are a popular method for accomplishing this in Go, which involves utilizing a slice of structs.

  • The input values (values) and the anticipated output (average) are both stored in a struct (testpair) defined by this method.
  • There are several test cases in a global slice of testpair structs (tests). Next, iterating over this slice, the TestAverage function computes the Average function for every pair and reports any differences.
  • Writing tests for floating-point numbers should include a range of scenarios, such as repeating numbers, random values, empty lists, and negative integers.

Example Functions as Tests

Example functions that work as executable tests and offer documentation for your packages can be created with Go.

Naming Convention: Example must come first in example functions.

Signature: They don’t accept any input parameters and don’t provide any output.

Location: They can be found in the _test.go files.

Output Verification: The go test tool will determine whether the actual output of an example function matches the values found following the // Output: line if it has one.

This example test will be successful if F1(10) actually produces 55 and F1(2) produces 1. A failure will be reported by Go Test if it does not match.

Testing HTTP Handlers

The net/http/httptest package is part of the standard library for Go and is used to test HTTP handlers, which is essential for web applications.

  • A new HTTP request (http.NewRequest) and a httptest.ResponseRecorder are created in this example in order to record the response.
  • It then uses handler.ServeHTTP to call the handler method (CheckStatusOK).
  • Lastly, the response body (rr.Body.String()) and recorded status code (rr.Code) are compared to the expected values.

General Testing Advice

Early Detection: Creating tests early in the development process can aid in finding flaws as soon as possible.

Error Checking: Because Go’s compiler is stringent and can identify a variety of mistakes (such as unused variables, missing imports, and incorrect operations) during the build process, debugging time is greatly reduced.

Edge Cases: Edge cases, such providing an empty list to a function that anticipates a slice of integers, should always be tested.

Documentation: While thorough documentation is not always necessary for good code, it is generally recommended to document everything, even the obvious.

Modular Code: Tests ought to be reusable and modular, just like regular code. It’s easier to test code that is organised into functions.

Production Readiness: Making Go apps production-ready requires a crucial step: proper panic recovery.

Test for Presence, Not Absence: Software testing can only reveal the existence of one or more defects, not their absence; you can never be certain that your code is error-free.

You can also read What Is Mean By Worker Pools In Go With Code Examples

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index