Golang Testing Examples | How to test GO Code?

How to write unit tests in GO?

You are done with your project/code and it looks great. What next? The next thing to do is to test your code to be sure it is doing what it is supposed to do. In software development we have unit testing which is basically a test written by a software developer to ensure function or classes meet its desired design and behave and operate as intended. You can test an entire module or just a function in your code. The main purpose of having tests in your code is to isolate each part of your program and demonstrate that these individual units of your code actually work as intended. Unit tests help identify problems that might be shipped to production if no thorough tests are done.

Software testing by developers is so vital that has led to a development process called Test Driven Development or TDD. TDD is a development process that requires that software requirements get converted to test cases before software is fully developed, and track all software development by repeatedly testing the software against all test cases. This is unlike what you would expect where software is developed first and tests are written later. This article will mainly focus on unit testing and help get started with writing tests in Go.

Advertisement

 

Prerequisites

 

Best Practices for Golang Testing

Go comes with a built-in testing package called “testing” .To be able to use this package, below requirements must be met .

  1. The filename containing the test must end with “_test.go” . For example if demo_test.go. The testing package checks for filename ending with _test.go to run the actual test.
  2. In the testing file, make sure to import the testing package.  Without the testing package, the test can not be run using the “go test” command.
  3. The testing file must have a function(s) that starts with the “Test” word followed by a name describing what kind of test you want to have. For example if you are testing a function that adds two numbers, the function name will be something like TestSumOfTwo(). Please note that the name describing what the test will do has to start with uppercase letter i.e TestSumOfTwo().
  4. The test function takes as an argument, a pointer to the testing package. Therefore the function will look like func TestSumOfTwo(*testing.T)
  5. To run the tests, use the “go test”  in the terminal . This command has to be run in the same module as the testing file.

The testing file should be put in the same package as the code being tested. This package will not be included while building your packages. It will be excluded when the go test command is run. Therefore do not be worried because these test codes will not be included in deployment code.

 

How to test in Go

In this section , we dive deep into how to get started with writing tests in Go. Using a code editor of your choice, I prefer VScode editor and I highly recommend it.Using a terminal follow the below instructions to get up and running.

Create a working directory

$ mkdir go_test

Move into the go_test directory

$ cd go_test/

Initialize a go module

Advertisement
$ go mod init example.com/go_test

Create a main.go file

touch main.go

Now that all that is set up, let's begin to code. We will start off by writing  functions that perform addition, subtraction , division and multiplication of numbers . Because these are basic math operations, we will create another folder at the root of our application called math. The math module will contain all the basic math operations functions together with the testing code. In your root directory issue the below commands.

Create a math folder with math.go and math_test.go files.

$ mkdir math && cd math && touch math.go math_test.go

math.go 

package math
 
func Addition(a, b int) int {
   return a + b
}
 
func Subtraction(a, b int) int {
   return a - b
}
 
func Multiplication(a, b int) int {
   return a * b
}
 
func Division(a, b int) float64 {
   return float64(a / b)
}

math_test.go

package math
 
import "testing"
 
func TestAddition(t *testing.T) {
   want := 10
 
   ans := Addition(5, 7)
 
   if ans != want {
       t.Fatalf("got %d, wanted %d", ans, want)
   }
}
 
func TestSubtraction(t *testing.T) {
   want := 0
 
   ans := Subtraction(5, 5)
 
   if ans != want {
       t.Fatalf("got %d, wanted %d", ans, want)
   }
}
 
func TestMultiplication(t *testing.T) {
   want := 25
 
   ans := Multiplication(5, 5)
 
   if ans != want {
       t.Fatalf("got %d, wanted %d", ans, want)
   }
}
 
func TestDivision(t *testing.T) {
   want := 1.0
 
   ans := Division(5, 5)
 
   if ans != want {
       t.Fatalf("got %f, wanted %f", ans, want)
   }
}

Explanation

The above unit test looks very similar in terms of code execution. We first of all start identifying the package that our code is hosted in, i.e. package math. We then import the testing package with import “testing”.

In the unit test, we define the functions that all start with the TestXxx format and all take a  pointer to the testing package TestXxx(t *testing.T).

Since we already know what results we want for each and every unit test, we assign the <b>want</b> variable to the expected result for each math operation. The <b>ans</b> variable gets assigned the response to each respective function that we are testing. Please note that we do not import the Addition, Subtraction, Multiplication and Division functions. In Go if a function starts with a capital letter, it is visible to any code in the same package. In this case,math is the package.

We then compare each response from these respective functions with the expected results.

Example

if ans != want {
     t.Fatalf("got %q, wanted %q", ans, want)
}

Before running our test, we need to add some code in our main.go file. The code in main.go basically runs the functions in the math package.

Advertisement

main.go

package main
 
import (
   "fmt"
 
   math "example.com/go_test/math"
)
 
func main() {
   fmt.Println("Go testing ...")
   a := 5
   b := 5
 
   sum := math.Addition(a, b)
   sub := math.Subtraction(a, b)
   mul := math.Multiplication(a, b)
   div := math.Division(a, b)
 
   fmt.Printf("The sum of %d and %d is %d \n", a, b, sum)
   fmt.Printf("The subtraction of %d from %d is %d \n", a, b, sub)
   fmt.Printf("The multiplication of %d by %d is %d \n", a, b, mul)
   fmt.Printf("The division of %d and %d is %f \n", a, b, div)
}

Output:

To run the code in the main.go file, navigate to the root of your application if you haven't already and issue the below command.

$ go run main.go
Go testing ...
The sum of 5 and 5 is 10
The subtraction of 5 from 5 is 0
The multiplication of 5 and 5 is 25
The division of 5 and 5 is 1.000000

You will agree with me that this is not how we run the tests, that is true. The above command pretty much tests if our program runs successfully and there are no runtime errors.

 

Running tests

To run the tests, navigate to the math folder and issue the below command.

$ go test
PASS
ok      example.com/go_test/math        0.002s

The above output shows that all the tests have run and passed successfully. This is what we want, but you can print more information about each individual unit test by adding -v in the go test command. The v stands for verbose.

Advertisement
$ go test -v
=== RUN   TestAddition
--- PASS: TestAddition (0.00s)
=== RUN   TestSubtraction
--- PASS: TestSubtraction (0.00s)
=== RUN   TestMultiplication
--- PASS: TestMultiplication (0.00s)
=== RUN   TestDivision
--- PASS: TestDivision (0.00s)
PASS
ok      example.com/go_test/math        0.002s

 

Testing negative scenarios

In order to test the correctness of a function, we can pass values of types that these functions do not allow or expect. For example, the Addition() function expects the two arguments passed to it to be integers, but we can pass a string just to see if the test will fail or not.

Example

func TestAddition(t *testing.T) {
   want := 10
 
   ans := Addition(5, "5")
 
   if ans != want {
       t.Fatalf("got %d, wanted %d", ans, want)
   }
}

Output

$ go test
# example.com/go_test/math [example.com/go_test/math.test]
./math_test.go:8:21: cannot use "5" (untyped string constant) as int value in argument to Addition
FAIL    example.com/go_test/math [build failed]

Explanation

In the above example, we pass a string “5” to the Addition function and run the test again using the go test -v command. The above test fails because “5” is not the correct type to be passed to the Addition function and it is not possible to perform addition of string and int types.

 

Summary

This article introduces you to testing in go using the built in “testing” package. Testing software is a key ingredient for a robust software and there it is important to add tests to your code before shipping them to production. So far we have looked at testing code manually, but this process can be automated by remote servers like CircleCi and many others.

Advertisement

 

References

https://go.dev/doc/tutorial/add-a-test
https://pkg.go.dev/testing

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X