Software testing is an essential part in software development. Software testing is used to check if the software can be used effectively and also to check if the software is created correctly based on the specified requirements. In this Go language series tutorial we will create a test cases.
In Go, the software testing can be done inside file with _test.go
notation. This is the basic syntax to create a test in Go.
func TestFuncName(t *testing.T) {
// code for test case..
}
|
In this example, the multiply()
function is tested. This function is created inside main.go
file then this function is tested inside main_test.go
file.
Code inside main.go
.
package coolpow // multiply returns multiply result of two numbers func multiply(x, y int) int { return x * y } |
Code inside main_test.go
.
package coolpow import "testing" // create a test for multiply function func TestMultiply(t *testing.T) { // execute function var result int = multiply(3, 4) // give the expected result var expected int = 12 // if result is not equal the expected if result != expected { // show the expected and result value t.Error("Expected: ", expected, " Got: ", result) } } |
Execute the test by using go test
command. This is the output if the test is executed.
PASS ok github.com/nadirbasalamah/coolpow 3.489s |
Based on the test code above, the test function is created. Inside this function, the multiply()
function is called and stored inside result
variable then the value from result
and expected
is checked if these two values are equal. If the values are equal then the test is passed. Otherwise, if the values are not equal then the test is failed then the value from expected
and result
is shown.
This is the example if the test is failed.
package coolpow import "testing" // create a test for multiply function func TestMultiply(t *testing.T) { // execute function var result int = multiply(3, 4) // give the expected result var expected int = 11 // if result is not equal the expected if result != expected { // show the expected and result value t.Error("Expected: ", expected, " Got: ", result) } } |
Output (use go test
command)
--- FAIL: TestMultiply (0.00s) main_test.go:16: Expected: 11 Got: 12 FAIL exit status 1 FAIL github.com/nadirbasalamah/coolpow 3.584s |
This is the example of testing with many test cases.
package coolpow import "testing" // create a struct to store test case type testCase struct { dataOne int dataTwo int expected int } // create a test for multiply function func TestMultiply(t *testing.T) { // create test cases var testCases []testCase = []testCase{ {2, 2, 4}, {5, 6, 30}, {7, 7, 49}, {5, 8, 40}, } // execute test for many test cases for _, testCase := range testCases { var result int = multiply(testCase.dataOne, testCase.dataTwo) // if test failed, show the expected and result value if result != testCase.expected { t.Error("Expected: ", testCase.expected, " Got: ", result) } } } |
Output
PASS ok github.com/nadirbasalamah/coolpow 3.477s |
Based on the code above, the dedicated struct to store test case is created. Inside the test function, many test cases is created in slice of testCase
. The test for each test case is executed using for range
.
Code coverage test is a test to ensure if all parts of code are necessary and there is no unused code (a.k.a. junk code). The code coverage test can be used to reduce the junk code so the code that is written is effective and efficient.
In this code coverage test example, the Pow()
function is created in main.go
file.
Code inside main.go
.
package coolpow // create a pow function func Pow(x, y float64) float64 { if y == 0 { return 1 } else if y == 1 { return x } else { var result float64 = 1 for i := 0; i < int(y); i++ { result *= x } return result } } |
The test for Pow()
function is created inside main_test.go
.
Code inside main_test.go
.
package coolpow import "testing" // create a test for Pow() function func TestPow(t *testing.T) { var result float64 = Pow(2, 3) var expected float64 = 8 if result != expected { t.Error("Expected: ", expected, " Got: ", result) } } |
To execute a code coverage test use go test -cover
command.
PASS coverage: 75.0% of statements ok github.com/nadirbasalamah/coolpow 3.612s |
Based on the output, the result of code coverage test is 75.0%.
There are other commands that can be used to execute code coverage test.
go test -coverprofile
: Execute code coverage test then save the result in dedicated file.
go tool cover -html
: Execute code coverage test then save the result in dedicated file. The result can be viewed in a web page.
This is the result from go test -coverprofile result.txt
command. The test result is saved inside result.txt
file.
mode: set github.com/nadirbasalamah/coolpow/main.go:4.32,5.12 1 1 github.com/nadirbasalamah/coolpow/main.go:5.12,7.3 1 0 github.com/nadirbasalamah/coolpow/main.go:7.8,7.19 1 1 github.com/nadirbasalamah/coolpow/main.go:7.19,9.3 1 0 github.com/nadirbasalamah/coolpow/main.go:9.8,11.31 2 1 github.com/nadirbasalamah/coolpow/main.go:14.3,14.16 1 1 github.com/nadirbasalamah/coolpow/main.go:11.31,13.4 1 1 |
This is the result from go tool cover -html result.txt
. The result is shown in a web page.
Benchmarking is an activity to measure the performance of a code. Benchmarking is used to ensure the code can be executed efficiently. This is the basic syntax to create a benchmark in Go.
func BenchmarkFuncName(b *testing.B) {
// code for benchmarking
}
|
Before the benchmark is created, the another function called OtherPow()
is created inside main.go
.
// create a OtherPow function // using math package to calculate pow func OtherPow(x, y float64) float64 { return math.Pow(x, y) } |
The OtherPow()
function is tested in main_test.go
.
// create a test for OtherPow() function func TestOtherPow(t *testing.T) { var result float64 = OtherPow(2, 3) var expected float64 = 8 if result != expected { t.Error("Expected: ", expected, " Got: ", result) } } |
Output (use go test
command)
PASS ok github.com/nadirbasalamah/coolpow 4.048s |
The benchmark is created for two functions including Pow()
and OtherPow()
in main_test.go
file.
// create a benchmark for Pow() function func BenchmarkPow(b *testing.B) { for i := 0; i < b.N; i++ { Pow(4, 3) } } // create a benchmark for OtherPow() function func BenchmarkOtherPow(b *testing.B) { for i := 0; i < b.N; i++ { OtherPow(4, 3) } } |
To execute a benchmark, use go test -bench .
command. This is the result of the benchmark.
goos: windows goarch: amd64 pkg: github.com/nadirbasalamah/coolpow BenchmarkPow-4 70403528 15.7 ns/op BenchmarkOtherPow-4 16018756 80.2 ns/op PASS ok github.com/nadirbasalamah/coolpow 10.247s |
Based on the output, there are two results from the benchmark:
The benchmark result for Pow()
function (BenchmarkPow-4
) performs an execution 70403528 times in 15.7 nano second per operation.
The benchmark result for OtherPow()
function (BenchmarkOtherPow-4
) performs an execution 16018756 times in 80.2 nano second per operation.
This is the another example of creating benchmarks.
// create a benchmark for Pow() function // for 2^10 func BenchmarkPow10(b *testing.B) { for i := 0; i < b.N; i++ { benchmarkPow(10, b) } } // create a benchmark for OtherPow() function // for 2^10 func BenchmarkOtherPow10(b *testing.B) { for i := 0; i < b.N; i++ { benchmarkOtherPow(10, b) } } // create a benchmark for Pow() function // for 2^100 func BenchmarkPow100(b *testing.B) { for i := 0; i < b.N; i++ { benchmarkPow(100, b) } } // create a benchmark for OtherPow() function // for 2^100 func BenchmarkOtherPow100(b *testing.B) { for i := 0; i < b.N; i++ { benchmarkOtherPow(100, b) } } // create a private function // so the function is not directly invoked // if the benchmark is executed func benchmarkPow(num float64, b *testing.B) { for i := 0; i < b.N; i++ { Pow(2, num) } } func benchmarkOtherPow(num float64, b *testing.B) { for i := 0; i < b.N; i++ { OtherPow(2, num) } } |
Output (use go test -bench .
command)
goos: windows goarch: amd64 pkg: github.com/nadirbasalamah/coolpow BenchmarkPow10-4 10000 312663 ns/op BenchmarkOtherPow10-4 10000 1200028 ns/op BenchmarkPow100-4 10000 2518267 ns/op BenchmarkOtherPow100-4 10000 851653 ns/op PASS ok github.com/nadirbasalamah/coolpow 68.471s |
Based on the output, the Pow()
function is more efficient for smaller input like 10. The OtherPow()
function is more efficient for larger input like 100.
I hope this article is helpful to learn testing and benchmarking in Go Programming Language.
Article Contributed By :
|
|
|
|
741 Views |