DEV Community

nadirbasalamah
nadirbasalamah

Posted on

Golang Tutorial - 11 Testing

Software Testing

When creating a software, a mistake can be found when before or even after software is released. A mistake that occured in a software could be an error, bug and other similar things. Many potential mistakes in a software can be evaluated by testing a software itself. Software testing is not only to make sure that the software can be used effectively without any errors or bugs but also to ensure that software is suitable with the user's requirement.

Testing in Go

Test a software in Go can be done by creating a file with _test.go extension. This file must located in the same package with the object or program that need to be tested. To create a test in test file, create a function with the Test..(t *testing.T) form. To run a test, use go test command.

Here it is the example of simple testing of sum operation:

main.go

package main

import "fmt"

func main() {
    fmt.Println("The result of 12 + 14 = ", sum(12, 14))
}

//create a sum function
func sum(x, y int) int {
    return x + y
}

Enter fullscreen mode Exit fullscreen mode

main_test.go

package main

import "testing"
//create a test
func TestSum(t *testing.T) {
    result := sum(12, 14) //get the result
    expected := 26
    if result != expected {
        t.Error("Expected", expected, "Got", result)
    }
}

Enter fullscreen mode Exit fullscreen mode

Output (use go test):

PASS
ok      review-again/uji        4.023s
Enter fullscreen mode Exit fullscreen mode

Other example if the test is failed.
main_test.go

package main

import "testing"

func TestSum(t *testing.T) {
    result := sum(12, 14)
    expected := 36 //change the expected value
    if result != expected {
        t.Error("Expected", expected, "Got", result)
    }
}

Enter fullscreen mode Exit fullscreen mode

Output:

--- FAIL: TestSum (0.00s)
    main_test.go:9: Expected 36 Got 26
FAIL
exit status 1
FAIL    review-again/uji        4.670s
Enter fullscreen mode Exit fullscreen mode

The test can be customized by creating a custom struct that consists of test cases and the expected results.

package main

import "testing"

func TestSum(t *testing.T) {
    //create a custom struct
    type testSample struct {
        data1  int
        data2  int
        answer int
    }

    //create a testcases that consist of testSamples
    testCases := []testSample{
        testSample{12, 14, 26},
        testSample{5, 5, 10},
        testSample{45, 45, 90},
    }

    //run a test for each test case
    for _, v := range testCases {
        result := sum(v.data1, v.data2)
        if result != v.answer {
            t.Error("Expected: ", v.answer, "Got: ", result)
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Output:

PASS
ok      review-again/uji        4.055s
Enter fullscreen mode Exit fullscreen mode

When creating a package or library in Go, there is a test called example test which can be used to test the functionality of a package.

To create a example test, lets create a simple package called simplesqrt then create a file main.go to create a function that will be tested.

main.go (inside directory called simplesqrt)

package simplesqrt

import "math"

//SquareRoot returns square root of number
func SquareRoot(f float64) float64 {
    return math.Pow(f, 0.5)
}
Enter fullscreen mode Exit fullscreen mode

Then create a test file called main_test.go. The example test must begin with Example...

main_test.go

package simplesqrt

import "fmt"

//The usage of SquareRoot Function
func ExampleSquareRoot() {
    fmt.Println("The result of square root of 16 = ", SquareRoot(16))
    //Output: The result of square root of 16 =  4
}
Enter fullscreen mode Exit fullscreen mode

The test can be run using go test command.
Output (use go test command):

PASS
ok      review-again/simplesqrt 4.666s
Enter fullscreen mode Exit fullscreen mode

The test can be checked in Godoc (Golang Documentation for packages) locally by godoc -http :8080.
After that, open a web browser and go to localhost:8080/pkg/<package location>/ then the example test looked like this.
Example Test

Code coverage is also available in Go, Code coverage basically measures the coverage of code to make sure the code that written is useful and to minimize the potential of junk code or useless code.

Here it is the example of code coverage test:
fizbuz.go

package fizbuz

func FizBuz(i int) string {
    if i%3 == 0 && i%5 == 0 {
        return "FizzBuzz"
    } else if i%3 == 0 {
        return "Fizz"
    } else if i%5 == 0 {
        return "Buzz"
    } else {
        return "null"
    }
}
Enter fullscreen mode Exit fullscreen mode

fizbuz_test.go

package fizbuz

import "testing"

func TestFizBuz(t *testing.T) {
    result := FizBuz(15)
    if result != "FizzBuzz" {
        t.Error("Expected", "FizzBuzz", "Got", result)
    }
}

Enter fullscreen mode Exit fullscreen mode

To test the coverage of a code (in this case is FizBuz() function) can be done by these commands:

  • go test -cover: This command is used to run a coverage test then print the result to the console.
  • go test -coverprofile c.out: This command is used to run a coverage test then write the result in c.out file. The c.out can be any file.
  • go tool cover -html c.out: This command is used to run a coverage test then show the result in web page. With this command. The coverage of a code can be analyzed which part of code is executed or not.

Output (go test -cover):

PASS
coverage: 28.6% of statements
ok      review-again/uji/fizbuz 4.669s
Enter fullscreen mode Exit fullscreen mode

Output (inside c.out file):

mode: set
review-again/uji/fizbuz/fizbuz.go:3.27,4.26 1 1
review-again/uji/fizbuz/fizbuz.go:4.26,6.3 1 1
review-again/uji/fizbuz/fizbuz.go:6.8,6.21 1 0
review-again/uji/fizbuz/fizbuz.go:6.21,8.3 1 0
review-again/uji/fizbuz/fizbuz.go:8.8,8.21 1 0
review-again/uji/fizbuz/fizbuz.go:8.21,10.3 1 0
review-again/uji/fizbuz/fizbuz.go:10.8,12.3 1 0
Enter fullscreen mode Exit fullscreen mode

Output (using go tool cover -html c.out):
Code Coverage

Benchmarking in Go

Benchmarking is basically measuring the performance of software to make sure the software can be used efficiently. Benchmarking in Go can be done by creating a function with Benchmark...(b *testing.B) notation.

Here it is the example of benchmarking in Go, in this case, the SquareRoot() and AnotherSquareRoot() function used for benchmarking example.
main.go

package simplesqrt

import "math"

//SquareRoot returns square root of number
func SquareRoot(f float64) float64 {
    return math.Pow(f, 0.5)
}

//AnotherSquareRoot return square root of number using math.Sqrt()
func AnotherSquareRoot(f float64) float64 {
    return math.Sqrt(f)
}

Enter fullscreen mode Exit fullscreen mode

main_test.go

package simplesqrt

import (
    "fmt"
    "testing"
)

//The usage of SquareRoot Function
func ExampleSquareRoot() {
    fmt.Println("The result of square root of 16 = ", SquareRoot(16))
    //Output: The result of square root of 16 =  4
}

//Benchmark for SquareRoot() function
func BenchmarkSquareRoot(b *testing.B) {
    for i := 0; i < b.N; i++ {
        SquareRoot(16)
    }
}

//Benchmark for AnotherSquareRoot() function
func BenchmarkAnotherSquareRoot(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AnotherSquareRoot(16)
    }
}

Enter fullscreen mode Exit fullscreen mode

Output (use go test -bench .):

goos: windows
goarch: amd64
pkg: review-again/simplesqrt
BenchmarkSquareRoot-4           200000000                7.63 ns/op
BenchmarkAnotherSquareRoot-4    2000000000               0.44 ns/op
PASS
ok      review-again/simplesqrt 9.401s
Enter fullscreen mode Exit fullscreen mode

Based on the output, there are two benchmark results:

  • BenchmarkSquareRoot-4 has done 200000000 operations with 7.63 nano second per operation
  • BenchmarkAnotherSquareRoot-4 has done 2000000000 operations with 0.44 nano second per operation

The output can be explained like this:

//name of benchmark func       //num of operations     //execution time
BenchmarkSquareRoot-4           200000000                7.63 ns/op
BenchmarkAnotherSquareRoot-4    2000000000               0.44 ns/op
Enter fullscreen mode Exit fullscreen mode

Notice that the AnotherSquareRoot() function is more efficient than SquareRoot() function. Because the AnotherSquareRoot() function has a smaller number in execution time.

Notes

  • Documentation for test package can be checked here

This is the final part of golang basic tutorial series in this blog. I hope this golang basic tutorial series is helpful for learning the Go programming language 😀.

What's Next ?

  • Practice by coding, for example you can solve some problems in online coding exercise website like hackerrank or other related website.
  • Learn more about the Golang best practices.

I hope this article helpful for helping to learn the Go programming language. If you have any thoughts or feedbacks, you can write it in the discussion section below.

Discussion (0)