共计 4096 个字符,预计需要花费 11 分钟才能阅读完成。
测试对于互联网应用软件开发来说非常重要,它对软件可靠性保证具有重要意义,通过测试能够尽可能发现并改正软件中的错误,提高软件质量。
这里我们主要讲解 Go 语言如何实现单元测试和性能测试。
go 语言中自带有一个轻量级的测试框架 testing 和自带的 go test 命令来实现单元测试和性能测试,testing 框架和其他语言中的测试框架类似,你可以基于这个框架写针对相应函数的测试用例,也可以基于该框架写相应的压力测试用例,那么接下来让我们一一来看一下怎么写。
单元测试
创建目录 test,在目录下创建 add.go、add_test.go 两个文件,add_test.go 为单元测试文件。
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
}
然后在项目目录下运行 go test - v 就可以看到测试结果了
=== 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
如果看到 PASS 字样证明测试通过,FAIL 字样表示测试失败。
使用 testing 库的测试框架需要遵循以下几个规则如下:
文件名必须是_test.go 结尾的,这样在执行 go test 的时候才会执行到相应的代码
你必须 import testing 这个包
所有的测试用例函数必须是 Test 开头
测试用例会按照源代码中写的顺序依次执行
测试函数 TestXxx() 的参数是 testing.T,我们可以使用该类型来记录错误或者是测试状态
测试格式:func TestXxx (t *testing.T),Xxx 部分可以为任意的字母数字的组合,但是首字母不能是小写字母 [a-z],例如 Testintdiv 是错误的函数名。
函数中通过调用 testing.T 的 Error, Errorf, FailNow, Fatal, FatalIf 方法,说明测试不通过,调用 Log 方法用来记录测试的信息。
性能测试或压力测试
压力测试用来检测函数 (方法)的性能,和编写单元功能测试的方法类似, 此处不再赘述,但需要注意以下几点:
压力测试用例必须遵循如下格式,其中 XXX 可以是任意字母数字的组合,但是首字母不能是小写字母
func BenchmarkXXX(b *testing.B) {…}
go test 不会默认执行压力测试的函数,如果要执行压力测试需要带上参数 -test.bench,语法:-test.bench=”test_name_regex”, 例如 go test -test.bench=”.*” 表示测试全部的压力测试函数
在压力测试用例中, 请记得在循环体内使用 testing.B.N, 以使测试可以正常的运行
文件名也必须以_test.go 结尾
在 test 目录下创建 reflect_test.go
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 < b.N; 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 < b.N; i++ {
s = new(Student)
}
_ = s
}
func BenchmarkReflect_Set(b *testing.B) {
var s *Student
sv := reflect.TypeOf(Student{})
b.ResetTimer()
for i := 0; i < b.N; 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 < b.N; 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 < b.N; 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 < b.N; i++ {
s = new(Student)
s.Name = “Jerry”
s.Age = 18
s.Class = “20005”
s.Score = 100
}
}
在 test 目录下,执行:
go test reflect_test.go -test.bench=”.*”
结果如下
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
上面的结果显示我们没有执行任何 TestXXX 的单元测试函数,显示的结果只执行了压力测试函数,以第三行为例
BenchmarkReflect_New 函数执行了 20000000 次,每次的执行平均时间是 84.9 纳秒。最后一行 command-line-arguments 10.982s,代表总的执行时间为 10.982s。
如果只想对某个函数测试,以 BenchmarkReflect_New 为例,执行命令
go test reflect_test.go -test.bench=”BenchmarkReflect_New”
结果为:
goos: windows
goarch: amd64
BenchmarkReflect_New-4 20000000 84.9 ns/op
PASS
ok command-line-arguments 2.490s
如果测试整个目录下的所有测试执行:
go test -test.bench=”.*”
如果想显示内存分配的次数和大小添加 -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
后两列代表分配的内存大小和次数(48 B/op 1 allocs/op)
推荐 gotests
它是编写 Go 测试的一个 Golang 命令行工具,可以根据目标源文件的函数和方法签名生成表驱动的测试。将自动导入测试文件中的任何新依赖项。
参考:
https://studygolang.com/stati…
https://www.cnblogs.com/yjf51…
links
目录