Go Testing

Learn via video courses
Topics Covered

Overview

The modern programming language has native facilities for creating and running test cases against the code. Along with the go test command, the go language also comes with its own set of tools in the form of golang testing modules. This article will go over all the fundamentals of unit test cases and deploy them as well.

Introduction

The unit test is a function that is used for golang testing the specific piece of code from a package or a program. The main task of the unit test is to check the application and the working of the go programming language. In this article, we will be creating a small program and will run a series of test codes using the command line of the go language and the testing package of the go language.

Prerequisites

For completing this tutorial, we will be needing the following:

  • Hands-on on-the-go language along with theoretical concepts of go language
  • A higher version of go should be installed preferably, version 1.11 or higher on the local machine. You can read the documentation and follow the instructions given accordingly.

A Basic Go App with a Unit Test

In this section, we will take a simple example that is unoptimized and that calculates the Fibonacci sequence in the go language.

Now if we save the program named as main.go in the fib directory then we can run it by executing the command go run .\fib.

For creating a test for this program, we have to create a file in the same directory which is named main_test.go along with the suffix test just to give us the hint that this file is for testing. The code for the main_test.go file is given below:

Explanation:
In a unit test file, the function that is starting with the capital T is very important. This function indicates which function will be used in a unit test case. The functions that don’t follow the naming convention are mainly considered internal to the suite test. These are functions that are called from within the test function but aren’t executed directly as a part of the test suite run.

The unit test can import every public function that is there in the file. If you consider this case, then all the public methods are available in the main.go file. Here, each function takes in the variable of the testing type T which can further be used for checking and raising the error whenever any test case fails. The testing object T can also be used for logging the message for any error if needed.

Testing Flags

The flags in golang testing are used to control the flow of the program during initialization.

The command go test accepts flags that apply to go test itself and flags that apply to the test binary that is produced.

In the articles, we will cover a few basic flags like -v, and -run.

FlagDescription
-vVerbose output: log all tests as they are run. Also, print all text from Log and Logf calls even if the test succeeds.
-runRun only those tests, examples, and fuzz tests matching the regular expression.
-benchRun only those benchmarks matching a regular expression. By default, no benchmarks are run.
-coverprofileWrite a coverage profile to the file after all tests have passed.

Please refer to this link for all the available flags.

Running Go Unit Tests

To run the Go unit test, we just have to type go test <app> where the tag <app> is the name of the directory that contains the application. The result of this is printed in the console.

In the rightmost column, the timestamp is considered the total time taken for running the tests. In case the test fails, the location of that is printed in the console along with the error message.

Running Subtests in Go

The golang testing module of the go provides a way for running the subsets of the tests instead of running everything together. The simplest way of doing this is to invoke the test by its name, for example, the only function in the above test suite can be invoked by executing the following command in the relevant source directory.

The command given would run the test only for the function FibInt and no other function.

Another way in which the test cases can be executed is by bypassing the argument in the test runner that can further be used by the test. Now copy and paste the code given below in the test file:

In this example, the command t.Run() takes in two arguments respectively, the first argument matches with the parameter that is passed in the go test, and the second argument is the name of the test function.

Note: that here the function TestFibInt is renamed to tFibInt so that it is directly executed and invoked by the test runner.

This test can be executed in several different ways as given below:

  • go test -run All: runs all the test functions with the word All in the name. In this example, the first argument of the TestAll. t.Run() function will be ignored because no parameter is passed to match against the same.

  • go test -run All/a=0: it is the same as above except that the function t.Run() will be executed only if the first parameter which is string has the matching a= in it. For this, it will run the function tFibInt as a partial match worker too.

  • go test -run All/a=1: it is similar to the above function but it will execute nothing. This is because the t.Run() function has the first parameter that matches with the a=1.

Writing Coverage Tests in Go

When writing the test for the go code, we must know how much of the actual code covers the test cases. This is mainly referred to as coverage. In this, we will take a different example. Copy and paste the code given below:

Now execute the following command to calculate the test coverage for the current unit test:

After executing the above command, we will receive the following output:

Output:

This data will be saved by Go language in the file coverage.out. We can now present this data in the web browser.

Now execute the following command given below:

After executing the above command, the web browser will be opened and the result will be rendered onto the screen.

If you check the output on your browser, you will notice the green and red text. Here the green text indicates the test coverage while the red text indicates the opposite of that.

Writing Benchmarks in Go

Benchmarking is used for measuring the performance of a function or a program. It allows us to compare the implementations and the impact of the changes that are made in the code so that by using that information, the code can be optimized accordingly. In the go language, the function that takes the func BenchmarkXxx(*testing.B) form is considered as a benchmark.

The command, go test will execute these benchmarks when the flag -bench is provided. These benchmarks are executed sequentially. Now that we know what is a benchmark, let's add it to the unit test. The first step is to open the file math_test.go by using the command:

The second step is to add the benchmark function as given in the code below:

This benchmark function should target the code b.N times, where N is the integer that can be changed according to the requirements. During the execution of the benchmark, the b.N is changed every time until the benchmark function is achieved.

This flag --bench also accepts the arguments in the form of the regular expression.

Now let's use the command go test to execute the benchmark again.

The . is used for matching every benchmark function in the file. When the above command is executed, we can see the output as given below:

Output:

In the output, the loop executed 10,000,000 times at a speed of 1.07 nanoseconds per loop:

Documenting your Go Code with Examples

The go language has a lot of focus when it comes to the documentation of the go code along with test cases. The code example adds importance both to the documentation and the testing of the code. Look at the example given below:

Output:

If you look at it, the example is tested along with the proper documentation of the code. The feature makes the unit test robust as well as improves documentation and readability.

Conclusion

  • The unit test is a function that is used for golang testing the specific piece of code from a package or a program. The main task of the unit test is to check the application and the working of the go programming language.
  • The testing module of the go provides a way for running the subsets of the tests instead of running everything together. The simplest way of doing this is to invoke the test by its name, for example, the only function in the above test suite can be invoked by executing the following command in the relevant source directory. go test -run FibInt
  • When writing the test for the go code, we must know how much of the actual code covers the test cases. This is mainly referred to as coverage.