Go unit testing and performance testing

Go unit testing and performance testing

Testing is very important to the development of Internet application software. It is of great significance to software reliability assurance. Through testing, it is possible to find and correct errors in the software as much as possible to improve software quality.

Here we mainly explain how the Go language implements unit testing and performance testing.

Go language comes with a lightweight testing framework testing and comes with the go test command to implement unit testing and performance testing. The testing framework is similar to testing frameworks in other languages. You can write corresponding functions based on this framework. Test cases, you can also write corresponding stress test cases based on this framework, so let's take a look at how to write them one by one.

unit test

Create a directory test, create two files add.go and add_test.go in the directory, add_test.go is the unit test file.

add_test.go

package test

import "testing"

func TestAdd(t *testing.T) {
   sum := Add(1, 2)
   if sum == 3 {
      t.Log("the result is ok")
   } else {
      t.Fatal("the result is wrong")
   }
}
func TestAdd1(t *testing.T) {
    t.Error("the result is error")
}

add.go

package test

func Add(a, b int) int {
   return a + b
}

Then run in the project directory to go test -vsee the test results

=== RUN TestAdd
--- PASS: TestAdd (0.00s)
    add_test.go:8: the result is ok
=== RUN TestAdd1
--- FAIL: TestAdd1 (0.00s)
    add_test.go:14: the result is error
FAIL
exit status 1
FAIL _/D_/gopath/src/ados/test 0.419s

If you see the word PASS to prove the test passed, the word FAIL means the test failed.

The test framework using the testing library needs to follow the following rules:

  • The file name must be at the _test.goend, so go testthat the corresponding code will be executed when it is executed
  • You must import testingthis package
  • All test case functions must be Testat the beginning
  • The test cases will be executed in the order written in the source code
  • TestXxx()The parameter of the test function is testing.Tthat we can use this type to record errors or test status
  • Test format: func TestXxx (t *testing.T), Xxxpart may be any combination of alphanumeric characters, but is not the first letter lowercase letters [AZ], for example, Testintdiva function name wrong.
  • By calling the function testing.Tof Error, Errorf, FailNow, Fatal, FatalIfthe method described does not pass the test, calling Logthe method for recording the test information.

Performance test or stress test

Stress testing is used to detect the performance of functions (methods). It is similar to the method of writing unit function tests. I will not repeat them here, but you need to pay attention to the following points:

  • The stress test case must follow the following format, where XXX can be any combination of letters and numbers, but the first letter cannot be a lowercase letter func BenchmarkXXX(b *testing.B) {...}
  • go testThe function that does not execute the stress test by default, if you want to perform the stress test, you need to bring parameters -test.bench, syntax:, -test.bench="test_name_regex"for example go test -test.bench=".*", to test all the stress test functions
  • In the stress test case, please remember to use it in the loop testing.B.Nso that the test can run normally
  • The file name must also _test.goend in

Create reflect_test.go in the test directory

package test

import (
   "reflect"
   "testing"
)

type Student struct {
   Name string
   Age int
   Class string
   Score int
}

func BenchmarkReflect_New(b *testing.B) {
   var s *Student
   sv := reflect.TypeOf(Student{})
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      sn := reflect.New(sv)
      s, _ = sn.Interface().(*Student)
   }
   _ = s
}
func BenchmarkDirect_New(b *testing.B) {
   var s *Student
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      s = new(Student)
   }
   _ = s
}
func BenchmarkReflect_Set(b *testing.B) {
   var s *Student
   sv := reflect.TypeOf(Student{})
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      sn := reflect.New(sv)
      s = sn.Interface().(*Student)
      s.Name = "Jerry"
      s.Age = 18
      s.Class = "20005"
      s.Score = 100
   }
}
func BenchmarkReflect_SetFieldByName(b *testing.B) {
   sv := reflect.TypeOf(Student{})
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      sn := reflect.New(sv).Elem()
      sn.FieldByName("Name").SetString("Jerry")
      sn.FieldByName("Age").SetInt(18)
      sn.FieldByName("Class").SetString("20005")
      sn.FieldByName("Score").SetInt(100)
   }
}
func BenchmarkReflect_SetFieldByIndex(b *testing.B) {
   sv := reflect.TypeOf(Student{})
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      sn := reflect.New(sv).Elem()
      sn.Field(0).SetString("Jerry")
      sn.Field(1).SetInt(18)
      sn.Field(2).SetString("20005")
      sn.Field(3).SetInt(100)
   }
}
func BenchmarkDirect_Set(b *testing.B) {
   var s *Student
   b.ResetTimer()
   for i := 0; i <bN; i++ {
      s = new(Student)
      s.Name = "Jerry"
      s.Age = 18
      s.Class = "20005"
      s.Score = 100
   }
}

In the test directory, execute:

go test reflect_test.go -test.bench=".*"

The result is as follows

goos: windows
goarch: amd64
BenchmarkReflect_New-4 20000000 84.9 ns/op
BenchmarkDirect_New-4 30000000 50.6 ns/op
BenchmarkReflect_Set-4 20000000 89.9 ns/op
BenchmarkReflect_SetFieldByName-4 3000000 552 ns/op
BenchmarkReflect_SetFieldByIndex-4 10000000 132 ns/op
BenchmarkDirect_Set-4 30000000 53.0 ns/op
PASS
ok command-line-arguments 10.982s

The above results show that we did not execute anyTestXXX unit test function, the displayed result only executed the stress test function, take the third line as an example

The BenchmarkReflect_New function was executed 20 million times, and the average time for each execution was 84.9 nanoseconds. The last line of command-line-arguments 10.982s, representing the total execution time of 10.982s.

If you only want to test a certain function, take BenchmarkReflect_New as an example, execute the command

go test reflect_test.go -test.bench="BenchmarkReflect_New"

The result is:

goos: windows
goarch: amd64
BenchmarkReflect_New-4 20000000 84.9 ns/op
PASS
ok command-line-arguments 2.490s

If all tests in the entire directory are executed:

go test -test.bench=".*"

If you want to display the number and size of memory allocation, add -benchmem

go test reflect_test.go -benchmem -test.bench=".*"

goos: windows
goarch: amd64
BenchmarkReflect_New-4 20000000 88.3 ns/op 48 B/op 1 allocs/op
BenchmarkDirect_New-4 30000000 53.8 ns/op 48 B/op 1 allocs/op
BenchmarkReflect_Set-4 20000000 90.9 ns/op 48 B/op 1 allocs/op
BenchmarkReflect_SetFieldByName-4 3000000 564 ns/op 80 B/op 5 allocs/op
BenchmarkReflect_SetFieldByIndex-4 10000000 135 ns/op 48 B/op 1 allocs/op
BenchmarkDirect_Set-4 30000000 52.4 ns/op 48 B/op 1 allocs/op
PASS
ok command-line-arguments 12.955s

The last two columns represent the size and number of allocated memory (48 B/op 1 allocs/op)

Recommended gotests

It is a Golang command line tool for writing Go tests, which can generate table-driven tests based on the function and method signatures of the target source file . Any new dependencies in the test file will be imported automatically.

reference:

https://studygolang.com/stati...

https://www.cnblogs.com/yjf51...

Reference: https://cloud.tencent.com/developer/article/1706185 Go unit testing and performance testing-Cloud + Community-Tencent Cloud